1.场景
在进行开发过程中,直接使用了Vue-Router来进行页面跳转,但是出现了一些奇奇怪怪的bug,特花时间来进行相关调研并记录,如有不严谨或不正确的地方,欢迎指正探讨。
问题
使用Vue-Router来进行页面跳转
使用this.$router.push() 地址栏的链接不变,Iframe的src不变,但是Iframe的内容发生变化。
使用this.$router.go(-1) 来进行跳转,地址栏链接改变,Iframe的src改变,Iframe的内容也发生变化。
使用this.$router.href()可以进行跳转,且地址栏发生改变
2.路由处理
说到路由跳转就不得不提Window.history 系列的Api了,常见的Vue-router等路由处理其本质也都是在通过该系列Api来进行页面切换操作。
本次我们讨论的就主要涉及 到Window.history.pushState和Window.history.go。
Window.history(下文将直接简称为history)指向一个History对象,表示当前窗口的浏览历史,History对象保存了当前窗口访问过的所有页面网址。
2.1History常见属性与方法
go() 接受一个整数为参数,移动到该整数指定的页面,比如history.go(1)相当于history.forward(),history.go(-1)相当于history.back(),history.go(0)相当于刷新当前页面
back() 移动到上一个访问页面,等同于浏览器的后退键,常见的返回上一页就可以用back(),是从浏览器缓存中加载,而不是重新要求服务器发送新的网页
forward() 移动到下一个访问页面,等同于浏览器的前进键
pushState()
pushState()需要三个参数:一个状态对象(state),一个标题(title)和一个URL。
*注意:pushState会改变url,但是并不会刷新页面,也就是说地址栏的url会被改变,但是页面仍保持当前。
总之,pushState()方法不会触发页面刷新,只是导致 History 对象发生变化,地址栏会有反应。
history.pushState({a:1},'page 2','2.html')
popState事件
每当同一个文档的浏览历史(即history对象)出现变化时,就会触发popstate事件。简单可以理解为,每次我们需要修改url 那么必定是先出发了popState事件,浏览器的地址栏随后才会发生改变。
注意,仅仅调用pushState()方法或replaceState()方法 ,并不会触发该事件,**只有用户点击浏览器倒退按钮和前进按钮,或者使用 JavaScript 调用History.back()、History.forward()、History.go()方法时才会触发。**另外,该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发。
2.2Vue-Router的实现
#push src/history/html5.js
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
this.transitionTo(location, route => {
pushState(cleanPath(this.base + route.fullPath))
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
}, onAbort)
}
function pushState (url, replace) {
saveScrollPosition();
// try...catch the pushState call to get around Safari
// DOM Exception 18 where it limits to 100 pushState calls
var history = window.history;
try {
if (replace) {
// preserve existing history state as it could be overriden by the user
var stateCopy = extend({}, history.state);
stateCopy.key = getStateKey();
history.replaceState(stateCopy, '', url);
} else {
history.pushState({ key: setStateKey(genStateKey()) }, '', url);
}
} catch (e) {
window.location[replace ? 'replace' : 'assign'](url);
}
}
#go src/history/html5.js
go (n: number) {
window.history.go(n)
}
以上是Vue-router再history模式下push和go的源码,可见其主要的实现是通过History Api来实现跳转的。
2.3Vue-Router是如何实现单页应用的呢?
vue-router 主要用来做单页面,即更改 url 无需刷新能够渲染部分组件达到渲染不同页面的效果,其中 history 模式监听 url 的变化的也是由 popstate 实现的,然后监听浏览器返回的方法也是大同小异。
原理是,A url-> B url,此时用户点击返回时,url 先回退到 A url,此时触发 popstate 回调,vuerouter 根据 next 回调传参是 false 判断需要修成 A url 成 B url,此时需要将进行 pushstate(B url),则此时就实现了阻止浏览器回退的效果
Ps:篇幅原因,源码在文章底部附上。
那么在进行了Iframe嵌套后会有什么不一样呢?