前言
虽然在已经写过了Vue实战篇,但还是觉得要单独的说一下Vue路由,所以就有了今天这篇深夜篇。
路由原理
路由实现了单页应用的更新视图但不重新请求页面,好处可想而知加载速度快、用户体验更好。先从两种路由模式说起。
路由的两种模式
-
hash模式
一般,我们将url中#和它之后的字符一起称为hash,通过window.location.hash来读取,他有两个特点。
- hash虽然出现在url中,但是不会被包括在HTTP请求中。它是用来指导浏览器动作的,对服务端没有影响。所以,改变hash不会重新加载页面。
- hash值的变化可以通过监听hashchange事件来得到window.addEventListener(“hashchange”, funcRef, false);每一次改变hash值,都会在浏览器的访问历史中增加一个记录。
-
history模式
history interface 是浏览器历史记录栈提供的接口,通过back()、forward()、go()等方法,我们可以读取到历史记录栈的信息,进行各种跳转。
这两种模式功能都非常好理解,我们直接通过mode
参数来设置,那么我们来看一下内部实现原理(部分关键源码),看一下Vuerouter类
export default class VueRouter {
mode: string; // 传入的字符串参数,指示history类别
history: HashHistory | HTML5History | AbstractHistory;
fallback: boolean; // 如浏览器不支持,'history'模式需回滚为'hash'模式
constructor (options: RouterOptions = {}) {
let mode = options.mode || 'hash' // 默认为'hash'模式
this.fallback = mode === 'history' && !supportsPushState // 通过supportsPushState判断浏览器是否支持'history'模式
if (this.fallback) {
mode = 'hash'
}
if (!inBrowser) {
mode = 'abstract' // 不在浏览器环境下运行需强制为'abstract'模式
}
this.mode = mode
// 根据mode确定history实际的类并实例化
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (process.env.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${mode}`)
}
}
}
以这种方式去对应路由方法然后执行他们实例对象的方法实现路由切换。
概述:
- 浏览器默认是hash模式,当浏览器不支持html5的history模式时,也会强制为hash模式;
- 当环境不是浏览器时,强制为abstract模式。当创建VueRouter实例后,VueRouter构造函数会通过传入对象options的mode参数,来调用对应的(HashHistory / HTML5History / AbstractHistory)构造函数,进而创建对应的history实例对象。
- 创建相应的history实例后,我们可以看到init函数里面会有对应的初始化操作。
两种模式的实现
由于时间关系小编这边就不去分析源码了
-
HashHistory
这是hash模式对应实例方法总体就是下面这个过程
- 触发$router.pash()
- 触发 HashHistory.push(),pushHash直接对window.location.hash赋值,hash值变化之后,浏览器访问历史中就会增加一个记录。
- 触发transitionTo() : 根据传入的location找到匹配的route,触发updateRoute().
- 触发updateRoute(): 将匹配的route赋给实例app的_route响应式属性, 当_route属性变化时,就会触发实例的rander函数,更新视图。
这是push方法是实现,那么对应的HashHistory还有replace方法实现类似,目的直接替换掉hash值
-
HTML5History
这种方式小编觉得更符合我们路由的那种实现感觉,页面回滚,不仅可以通过back()、forward()、go()方法来读取浏览器历史记录栈的信息,还新增两个方法:pushState()、replaceState()使得我们可以对浏览器历史记录栈进行修改。
两种模式的比较
hash模式
缺点:hash模式只能改变hash部分的内容,只能设置与当前同文档的URL
优点:hash部分是不会包含在http请求中的。
HTML5History模式
优点:
- 调用history.pushState()可以直接设置新的URL,可以是与当前URL同源的任意URL。
- pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串
- pushState可额外设置title属性供后续使用
缺点:
在history模式下:用户直接在地址栏中输入并回车,浏览器重启重新加载应用。这时history模式则会将URL修改得就和正常请求后端的URL一样,如果没有请求到资源,则会返回404。所有我们一般会自己添加一个404页面。