浅谈前端路由原理hash和history

封面

浅谈前端路由原理hash和history

  • 🎹序言
  • 🎸一、前端路由原理
    • 1、SPA
    • 2、什么时候需要路由
  • 🎷二、Hash模式
    • 1、定义
    • 2、网页url组成部分
      • (1)了解几个url的属性
      • (2)演示
    • 3、hash的特点
  • 🎺三、History模式
    • 1、定义
    • 2、与hash的区别
    • 3、history的API
    • 4、history的特点
    • 5、存在问题
    • 6、两者选择
  • 🎻四、结束语
  • 🐣彩蛋 One More Thing
    • 🏷️参考资料
    • 🏷️番外篇

🎹序言

众所周知, hashhistory 在前端面试中是很常考的一道题目。在学习本文内容之前,周一对 hashhistory 的认知可能就在 hashurl 里面多了个 # ,而 history 就不会。然后,我认知里还有一个是只有 history 才能做前后端分离,而 hash 跟前后端分离没有关系。然而,现实是……

吓到跌倒

对于前端路由来说, hashhistory 都可以用于前后端分离项目,且两者有各自的特点和各自的使用场景,在使用过程中主要要了解当前项目所处的场景,以便于更好地判断使用哪一种路由模式更佳。下面进入本文的讲解~😜

🎸一、前端路由原理

1、SPA

SPA,即单页面应用(Single Page Application)。所谓单页 Web 应用,就是只有一张 Web 页面的应用。单页应用程序 (SPA) 是加载单个 HTML 页面并在用户与应用程序交互时动态更新该页面的 Web 应用程序。浏览器一开始会加载必需的 HTMLCSSJavaScript ,所有的操作都在这张页面上完成,都由 JavaScript 来控制。

现如今,为了配合单页面 Web 应用快速发展的节奏,各类前端组件化技术栈层出不穷。近几年来,通过不断的版本迭代, vuereact 两大技术栈脱颖而出,成为当下最受欢迎的两大技术栈。

2、什么时候需要路由

对于现代开发的项目来说,稍微复杂一点的 SPA ,都需要用到路由。而 vue-router 正是 vue 的路由标配,且 vue-router两种模式hashhistory

下面就依据这两种模式来进行一一讲解。

🎷二、Hash模式

1、定义

hash 模式是一种把前端路由的路径用井号 # 拼接在真实 url 后面的模式。当井号 # 后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发 onhashchange 事件。

2、网页url组成部分

(1)了解几个url的属性

属性含义
location.protocal协议
location.hostname主机名
location.host主机
location.port端口号
location.patchname访问页面
location.search搜索内容
location.hash哈希值

(2)演示

下面用一个网址来演示以上属性:

//http://127.0.0.1:8001/01-hash.html?a=100&b=20#/aaa/bbb
location.protocal // 'http:'
localtion.hostname // '127.0.0.1'
location.host // '127.0.0.1:8001'
location.port //8001
location.pathname //'01-hash.html'
location.serach // '?a=100&b=20'
location.hash // '#/aaa/bbb'

3、hash的特点

  • hash变化会触发网页跳转,即浏览器的前进和后退。

  • hash 可以改变 url ,但是不会触发页面重新加载(hash的改变是记录在 window.history 中),即不会刷新页面。也就是说,所有页面的跳转都是在客户端进行操作。因此,这并不算是一次 http 请求,所以这种模式不利于 SEO 优化。hash 只能修改 # 后面的部分,所以只能跳转到与当前 url 同文档的 url

  • hash 通过 window.onhashchange 的方式,来监听 hash 的改变,借此实现无刷新跳转的功能。

  • hash 永远不会提交到 server 端(可以理解为只在前端自生自灭)。

🎺三、History模式

1、定义

history APIH5 提供的新特性,允许开发者直接更改前端路由,即更新浏览器 URL 地址而不重新发起请求

2、与hash的区别

我们用一个例子来演示, hashhistory 在浏览器下刷新时的区别。具体如下:

正常页面浏览

https://github.com/xxx 刷新页面https://github.com/xxx/yyy 刷新页面https://github.com/xxx/yyy/zzz 刷新页面

改造H5 history模式

https://github.com/xxx 刷新页面https://github.com/xxx/yyy 前端跳转,不刷新页面https://github.com/xxx/yyy/zzz 前端跳转,不刷新页面

3、history的API

下面阐述几种 HTML5 新增的 history API具体如下表:

API定义
history.pushState(data, title [, url])pushState主要用于往历史记录堆栈顶部添加一条记录。各参数解析如下:①data会在onpopstate事件触发时作为参数传递过去;②title为页面标题,当前所有浏览器都会忽略此参数;③url为页面地址,可选,缺少时表示为当前页地址
history.replaceState(data, title [, url])更改当前的历史记录,参数同上; 上面的pushState是添加,这个更改
history.state用于存储以上方法的data数据,不同浏览器的读写权限不一样
window.onpopstate响应pushState或者replaceState的调用

4、history的特点

对于 history 来说,主要有以下特点:

  • 新的 url 可以是与当前 url 同源的任意 url ,也可以是与当前 url 一样的地址,但是这样会导致的一个问题是,会把重复的这一次操作记录到栈当中。
  • 通过 history.state ,添加任意类型的数据到记录中。
  • 可以额外设置 title 属性,以便后续使用。
  • 通过 pushStatereplaceState 来实现无刷新跳转的功能。

5、存在问题

对于 history 来说,确实解决了不少 hash 存在的问题,但是也带来了新的问题。具体如下:

  • 使用 history 模式时,在对当前的页面进行刷新时,此时浏览器会重新发起请求。如果 nginx 没有匹配得到当前的 url ,就会出现 404 的页面。
  • 而对于 hash 模式来说, 它虽然看着是改变了 url ,但不会被包括在 http 请求中。所以,它算是被用来指导浏览器的动作,并不影响服务器端。因此,改变 hash 并没有真正地改变 url ,所以页面路径还是之前的路径, nginx 也就不会拦截。
  • 因此,在使用 history 模式时,需要通过服务端来允许地址可访问,如果没有设置,就很容易导致出现 404 的局面。

6、两者选择

下面我们再来介绍下在实际的项目中,如何对这两者进行选择。具体如下:

  • to B 的系统推荐用 hash ,相对简单且容易使用,且因为 hashurl 规范不敏感;
  • to C 的系统,可以考虑选择 H5 history ,但是需要服务端支持
  • 能先用简单的,就别用复杂的,要考虑成本和收益

🎻四、结束语

对于 hashhistory 来讲,要清楚两者的区别以及两者各自的使用场景,还有各自的使用特点和优缺点。以上文章只是对前端路由原理的浅谈,希望对大家有帮助~

另下方第三个彩蛋放了一篇关于实现 vue-router 的文章,学有余力的小伙伴有需要自取o!

🐣彩蛋 One More Thing

🏷️参考资料

jarvis👉在SPA项目的路由中,注意hash与history的区别

vue-router官方文档👉vue-router的两种模式

值得一看👉从使用到自己实现简单Vue Router看这个就行了

🏷️番外篇

  • 关注公众号星期一研究室,第一时间关注优质文章,更多精选专栏待你解锁~
  • 如果这篇文章对你有用,记得留个脚印jio再走哦~
  • 以上就是本文的全部内容!我们下期见!👋👋👋

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307899.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode145. 二叉树的后序遍历

一:题目 二:上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*…

.NET Core API文档管理组件 Swagger

Swagger这个优秀的开源项目相信大家都用过,不多介绍了,这里简单记录一下使用过程。开源地址:https://github.com/domaindrivendev/Swashbuckle.AspNetCore在项目中添加组件Install-Package Swashbuckle.AspNetCore下面用最少的代码完成接入&a…

「3.4w字」超保姆级教程带你实现Promise的核心功能

保姆级详解promise的核心功能📚序言📋文章内容抢先看📰一、js的同步模式和异步模式1. 单线程💡2. 同步模式💡(1)定义(2)图例3. 异步模式💡(1&…

leetcode199. 二叉树的右视图(层序遍历03)

一:题目 二:上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(n…

如何做好一个开源项目之徽章(二)

在上一篇【如何做好一个开源项目(一)】,笔者已经介绍过开源项目运作和维护的一些理念了,本篇开始,笔者将着重于介绍一些开源项目维护过程中的一些细节,比如徽章、构建等等。由于最近经常出差,所…

值得关注的HTML基础

值得关注的HTML基础🥳序言😋一、网页三大元素😜二、HTML简介1. 定义2. 发展历史😝三、HTML结构1. 引例阐述2. 特点3. HTML页面结构(1)DOCTYPE(2)html(3)head&…

leetcode637. 二叉树的层平均值(层序遍历04)

一:题目 二:上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(n…

leetcode429. N 叉树的层序遍历(层序遍历05)

一:题目 二&#xff1a;上码 /* // Definition for a Node. class Node { public:int val;vector<Node*> children;Node() {}Node(int _val) {val _val;}Node(int _val, vector<Node*> _children) {val _val;children _children;} }; */class Solution { publi…

10分钟带你探索css中更为奇妙的奥秘

10分钟带你探索css中更为奇妙的奥秘&#x1f4d6;序言&#x1f4c3;一、css是啥1. CSS是什么2. 诞生背景3. 基础规则&#xff08;1&#xff09;一些基础规则&#xff08;2&#xff09;其他重要的语法&#xff08;3&#xff09;选择器&#xff08;4&#xff09;层叠与继承1&…

将微服务部署到 Azure Kubernetes 服务 (AKS) 实践

介绍本文的目的是&#xff1a;通过使用 DockerHub 和 Azure Kubernetes Service (AKS) 将之前 使用 .NET 和 Docker 构建的微服务 部署到微软 Azure 云上&#xff0c;来介绍微服务的基本部署过程。推送到 Docker HubDocker Hub 是世界上最大的容器镜像库和社区。许多产品&#…

leetcode 515. 在每个树行中找最大值(层序遍历06)

一:题目 二&#xff1a;上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(n…

前端只是切图仔?来学学给开发人看的UI设计

给开发人看的UI设计&#x1f5bc;️序言&#x1f3a8; 一、背景1. 想做一个好的作品2. 没有专业UI&#x1f9f5;二、功能导向1. 设计中最重要的事2. 例子阐述2. 简约设计3. 设计简单的、完整的功能&#x1f9f6;三、设计原则1. 层级&#xff08;1&#xff09;层级是什么&#x…

Debian 新负责人发表演讲:Debian 的现状与面临的一些问题

喜欢就关注我们吧&#xff01;Debian GNU/Linux 年度主要的会议 DebConf20 已于近期举办&#xff0c;4 月份新当选的 Debian 项目负责人 Jonathan Carter 在会上发表了演讲&#xff0c;概述了 Debian 的现状与面临的一些问题。Debian 的财务稳定在 $896065 美元左右&#xff0c…

leetcode116. 填充每个节点的下一个右侧节点指针(层序遍历07)

一:题目 二:上码 /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node* next;Node() : val(0), left(NULL), right(NULL), next(NULL) {}Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}Node(int _val, Node* _left,…

程序员修神之路--略懂数据库集群读写分离而已

“灵魂拷问&#xff1a;解决数据库读写瓶颈有哪些解决方案呢&#xff1f;这些方案解决了什么问题呢&#xff1f;这些方案有那些优势和劣势呢&#xff1f;一个可以抵抗高并发流量系统的背后必定有一个高性能的数据库集群&#xff0c;就像每一个成功的男人背后总有一个强势的女人…

一张网页带你了解中秋节的前世今生

一张网页带你了解中秋节的前世今生&#x1f317;序言一、&#x1f319;题材选取1. 诗词赏析2. 原型图抢先看3. 界面设计二、&#x1f31b;编码阶段1. 项目目录结构2. html设计&#xff08;1&#xff09;nav结构设计&#xff08;2&#xff09;banner结构设计&#xff08;3&#…

leetcode117. 填充每个节点的下一个右侧节点指针 II(层序遍历08)

一&#xff1a;题目 二&#xff1a;上码 /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node* next;Node() : val(0), left(NULL), right(NULL), next(NULL) {}Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}Node(…

Linq 下的扩展方法太少了,您期待的 MoreLinq 来啦

一&#xff1a;背景 1. 讲故事前几天看同事在用 linq 给内存中的两个 model 做左连接&#xff0c;用过的朋友都知道&#xff0c;你一定少不了一个叫做 DefaultIfEmpty 函数&#xff0c;这玩意吧&#xff0c;本来很流畅的 from...in...join, 突然搞进来这么一个函数&#xff0c;…

紧跟月影大佬的步伐,一起来学习如何写好JS(上)

如何写好JS - 三大原则&#x1f302;序言一、☂️什么才是好的JS代码&#xff1f;二、&#x1f9f5; 写好JS的一些原则1. 各司其职&#x1f44b;&#xff08;1&#xff09;定义&#xff08;2&#xff09;例子阐述2. 组件封装&#x1f90f;&#xff08;1&#xff09;定义&#x…

leetcode104. 二叉树的最大深度(层序遍历09)

一:题目 二:上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*…