路由模式-Hash与History浅析
路由
参考
浅谈前端路由原理hash和history
前端路由-hash/history
前端路由的诞生
前端路由的兴起,使得页面渲染由服务器渲染变成了前端渲染。为什么这么说呢!请求一个 URL 地址时,服务器不需要拼接模板,只需返回一个 HTML 即可,一般浏览器拿到的 HTML 是这样的:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>
Demo
</title>
<link href="app.css" rel="stylesheet" />
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
这里空荡荡的只有一个 <div id="app"></div>
,以及一系列的 js 文件,所以说这个 HTML 是不完整的。我们看到的页面是通过这一系列的 js 渲染出来的,也就是前端渲染。前端渲染通过客户端的算力来解决页面的构建,很大程度上缓解了服务端的压力。
单页面开发是趋势,但也不能避重就轻,忽略前端渲染的缺点。由于服务器没有保留完整的 HTML,通过 js 进行动态 DOM 拼接,需要耗费额外的时间,不如服务端渲染速度快,也不利于 SEO 优化。所以说,实际开发中,不能盲目选择渲染方式,一定要基于业务场景。对于没有复杂交互,SEO 要求严格的网站,服务器渲染也是正确的选择。
前端路由路由有hash和history两种
hash模式
hash 模式是一种把前端路由的路径用井号 # 拼接在真实 url 后面的模式。当井号 # 后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发 onhashchange 事件。
location属性
//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'
改变hash值的方式
特点
hash变化会触发网页跳转(模拟跳转,实际由前端渲染)。
hash 可以改变 url ,但是不会触发页面重新加载(hash的改变是记录在 window.history 中),即不会刷新页面。也就是说,所有页面的跳转都是在客户端进行操作。因此,这并不算是一次 http 请求,所以这种模式不利于 SEO 优化。hash 只能修改 # 后面的部分,所以只能跳转到与当前 url 同文档的 url 。
hash 通过 window.onhashchange 的方式,来监听 hash 的改变。hash 模式路由就是利用 hashchange 事件监听 URL 的变化,从而进行 DOM 操作来模拟页面跳转。
hash 永远不会提交到 server 端(可以理解为只在前端自生自灭)
History模式
history API 是 H5 提供的新特性,允许开发者直接更改前端路由,即更新浏览器 URL 地址而不重新发起请求。
History API
window 对象通过 history 对象提供对览器历史记录的访问能力。
- history.length 出于安全考虑,History 对象不允许未授权代码访问历史记录中其它页面的 URLs,但可以通过 history.length 访问历史记录对象的长度。
- history.back() 回退到上一个历史记录,同浏览器后退键
- history.forward() 前进到下一个历史记录,同浏览器前进键
- history.go(n) 跳转到相应的访问记录;若 n > 0,则前进,若 n < 0,则后退,若 n = 0,则刷新当前页面
- history.pushState(state, title, URL) pushState 函数会向浏览器的历史记录中添加一条,history.length 的值会 +1,当前浏览器的 URL 变成了新的 URL。需要注意的是:仅仅将浏览器的 URL 变成了新的 URL,页面不会加载、刷新。
- history.replaceState(state, title, URL)
- replaceState 的使用与 pushState 非常相似,都是改变当前的 URL,页面不刷新。区别在于 replaceState 是修改了当前的历史记录项而不是新建一个,history.length 的值保持不变。
- window.onpopstate()
- 对于通过 history.pushState() 或 history.replaceState() 改变的历史记录,点击浏览器的后退键或前进键页面是没有反应的,那该如何控制页面渲染呢?为了配合 history.pushState() 或 history.replaceState(),HTML5 还新增了一个事件,用于监听 URL 历史记录改变:window.onpopstate()。
特点
- 新的 url 可以是与当前 url 同源的任意 url ,也可以是与当前 url 一样的地址,但是这样会导致的一个问题是,会把重复的这一次操作记录到栈当中。
- 通过 pushState 、 replaceState 来实现无刷新跳转的功能。
Hash与History模式对比
- History模式URL地址更直观,Hash模式可读性差
- Hash模式兼容性好,History模式不适用于不支持HTML5 history API的低版本浏览器
- SEO优化:搜索引擎对History API更友好,对单页应用搜索引擎优化更容易实现。
- 使用 History 路由模式实现路由功能需要更多的代码维护。使用 history 模式时,在对当前的页面进行刷新时,此时浏览器会重新发起请求。如果 nginx 没有匹配得到当前的 url ,就会出现 404 的页面。Hash模式没有真正改变url,不需要额外配置。
应用场景
- to B 的系统推荐用 hash ,相对简单且容易使用,且因为 hash 对 url 规范不敏感;
- to C 的系统,可以考虑选择 H5 history ,但是需要服务端支持;