众所周知,vue-router有两种模式,hash模式和history模式,这里来谈谈两者的区别。
hash模式
hash模式背后的原理是onhashchange事件,可以在window对象上监听这个事件:
window.onhashchange = function(event){ console.log(event.oldURL, event.newURL); let hash = location.hash.slice(1); document.body.style.color = hash; }
通过改变hash来改变页面字体颜色,一定程度上说明了原理。hash发生变化的url都会被浏览器记录下来,从而浏览器的前进后退都可以用了,点击后退或者前进时,页面字体颜色也会发生变化。这样一来,尽管浏览器没有请求服务器,但是页面状态和url一一关联起来。
history模式
HTML5引入了 history.pushState() 和 history.replaceState() 方法,它们分别可以添加和修改历史记录条目。这些方法通常与window.onpopstate 配合使用。
pushState 方法
使用 history.pushState() 可以改变referrer,它在用户发送 XMLHttpRequest 请求时在HTTP头部使用,改变state后创建的 XMLHttpRequest 对象的referrer都会被改变。因为referrer是标识创建 XMLHttpRequest 对象时 this 所代表的window对象中document的URL。
假设在 http://mozilla.org/foo.html 页面的console中执行了以下 JavaScript 代码:
window.onpopstate = function(e) { alert(2); } let stateObj = { foo: "bar", }; history.pushState(stateObj, "page 2", "bar.html");
这将使浏览器地址栏显示为 http://mozilla.org/bar.html,但并不会导致浏览器加载 bar.html ,甚至不会检查bar.html 是否存在。
假如现在用户在bar.html点击了返回按钮,将会执行alert(2)。
onpopstate
window.onpopstate是popstate事件在window对象上的事件处理程序.
调用history.pushState()或者history.replaceState()不会触发popstate事件. popstate事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮(或者在JavaScript中调用history.back()、history.forward()、history.go()方法),此外,a 标签的锚点也会触发该事件.
假如当前网页地址为http://example.com/example.html,则运行下述代码后:
window.onpopstate = function(event) { alert("location: " + document.location + ", state: " + JSON.stringify(event.state)); }; //添加并激活一个历史记录条目 http://example.com/example.html?page=1,条目索引为1 history.pushState({page: 1}, "title 1", "?page=1"); //添加并激活一个历史记录条目 http://example.com/example.html?page=2,条目索引为2 history.pushState({page: 2}, "title 2", "?page=2"); //修改当前激活的历史记录条目 http://ex..?page=2 变为 http://ex..?page=3,条目索引为3 history.replaceState({page: 3}, "title 3", "?page=3"); history.back(); // 弹出 "location: http://example.com/example.html?page=1, state: {"page":1}" history.back(); // 弹出 "location: http://example.com/example.html, state: null history.go(2); // 弹出 "location: http://example.com/example.html?page=3, state: {"page":3}
通过pushstate把页面的状态保存在state对象中,当页面的url再变回这个url时,可以通过event.state取到这个state对象,从而可以对页面状态进行还原,这里的页面状态就是页面字体颜色,其实滚动条的位置,阅读进度,组件的开关的这些页面状态都可以存储到state的里面。
history模式的问题
通过history api,丢掉了丑陋的#,但是它也有个问题:不怕前进,不怕后退,就怕刷新,(如果后端没有准备的话),因为刷新是实实在在地去请求服务器的,不玩虚的。 在hash模式下,前端路由修改的是#中的信息,而浏览器请求时是不带它玩的,所以没有问题.但是在history下,你可以自由的修改path,当刷新时,如果服务器中没有相应的响应或者资源,会分分钟刷出一个404来。