前端路由hash、history原理
本文参考https://www.cnblogs.com/tugenhua0707/p/10859214.html
先来看下后端路由的实现方式:
1. 浏览器向服务器发出请求。
2. 服务器监听到80端口,如果有请求过来,那么就解析url地址。
3. 服务器根据客户端的路由配置,然后就返回相应的信息(比如html字符串、json数据或图片等)。
4. 浏览器根据数据包的 Content-Type来决定如何解析数据。
缺点: 每次路由切换的时候都需要去刷新页面,然后发出ajax请求,然后将请求数据返回回来,那么这样每次路由切换都要刷新页面对于用户体验来说就不好了。因此为了提升用户体验,我们前端路由就这样产生了。它就可以解决浏览器不会重新刷新了。
那么前端路由也有2种模式,第一种是hash模式,第二种是history模式。我们来分别看下这两种知识点及区别如下:
1. hash模式
hash路由模式是这样的:http://xxx.abc.com/#/xx。 有带#号,后面就是hash值的变化。改变后面的hash值,它不会向服务器发出请求,因此也就不会刷新页面。并且每次hash值发生改变的时候,会触发hashchange事件。因此我们可以通过监听该事件,来知道hash值发生了哪些变化。比如我们可以如下简单的监听:
function hashAndUpdate () { // todo 匹配 hash 做 dom 更新操作 } window.addEventListener('hashchange', hashAndUpdate);
// 完整的url location.href // 当前URL的协议,包括 :; 比如 https: location.protocol /* 主机名和端口号,如果端口号是80(http)或443(https), 那就会省略端口号,比兔 www.baidu.com:8080 */ location.host // 主机名:比如:www.baidu.com location.hostname // 端口号;比如8080 location.port // url的路径部分,从 / 开始; 比如 https://www.baidu.com/s?ie=utf-8,那么 pathname = '/s'了 location.pathname // 查询参数,从?开始;比如 https://www.baidu.com/s?ie=utf-8 那么 search = '?ie=utf-8' location.search // hash是页面中的一个片段,从 # 开始的,比如 https://www.baidu.com/#/a/b 那么返回值就是:"#/a/b" location.hash
hash 和 pushState 对比有如下缺点:
1. hash只能修改url的片段标识符的部分。并且必须从#号开始,但是pushState且能修改路径、查询参数和片段标识符。pushState比hash更符合前端路由的访问方式,更加优雅(因为不带#号)。
2. hash必须和原先的值不同,才能新增会话浏览历史的记录,但是pushState可以新增相同的url的记录
2. history模式
HTML5的History API为浏览器的全局history对象增加了该扩展方法。它是一个浏览器的一个接口,在window对象中提供了onpopstate事件来监听历史栈的改变,只要历史栈有信息发生改变的话,就会触发该事件。提供了如下事件:
window.addEventListener('popstate', function(e) { console.log(e) });
history提供了两个操作历史栈的API: history.pushState 和 history.replaceState
history.pushState(data[,title][,url]); // 向历史记录中追加一条记录
history.replaceState(data[,title][,url]); // 替换当前页在历史记录中的信息。
如上html5中新增了上面这两个方法,该两个方法也可以改变url,页面也不会重新刷新。下面我们也可以来做个demo,来监听下popstate事件,现在在我js里面放入如下js代码:
window.addEventListener('popstate', function(e) { console.log(e)
hash模式的特点:
hash模式在浏览器地址栏中url有#号这样的,比如(http://localhost:3001/#/a). # 后面的内容不会传给服务端,也就是说不会重新刷新页面。并且路由切换的时候也不会重新加载页面。
history模式的特点:
浏览器地址没有#, 比如(http://localhost:3001/a); 它也一样不会刷新页面的。但是url地址会改变。