但凡是使用过vue-router的前端开发工作者,都知道Vue-router包括两种实现模式:hash和history。为了对这两种模式有更直观的认识,我选择简略阅读源码并在此记录。本篇先从模式参数mode入手。
vue-router是Vue框架的路由插件,下面从源码入手,学习一下vue-router是如何实现两种模式的。
模式参数:mode
使用方式:
const router = new VueRouter({
mode: 'history',
routes: [...]
})
创建VueRouter实例的时候,直接将mode以构造函数参数的形式传入,在VueRouter类定义(src/index.js)中,使用如下:
export default class VueRouter {
mode: string;//传入的string类型
history: HashHistory | HTML5History | AbstractHistory; //实际调用的对象属性
matcher: Matcher; // url正则匹配方法
fallback: boolean; // 如果浏览器不支持,history需要回滚为hash模式
...
let mode = options.mode || 'hash' //默认是hash模式
this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
if (this.fallback) {
mode = 'hash' // 传入模式为history,但是浏览器不支持,则回滚
}
if (!inBrowser) {
mode = 'abstract' // 不在浏览器环境下,强制设置为‘abstract’
}
this.mode = mode
// 根据mode的值,确定要使用的类,并实例化
switch(this.mode) {
case 'history':
this.history = new HTML5History(this, option.base)
break;
case 'hash:
this.history = new HashHistory(this, option.base, this.fallback)
break;
case 'abstract':
this.history = new AbstractHistory(this, option.base)
break;
default:
...
}
// 通过mode确定好history实例后,进行实例的初始化和监听
init (app: any /* Vue component instance */) {
const history = this.history
// 根据history的类别执行相应的初始化操作和监听
if (history instanceof HTML5History) {
// 'history'模式初始化
history.transitionTo(history.getCurrentLocation())
} else if (history instanceof HashHistory) {
const setupHashListener = () => {
history.setupListeners()
}
// 'hash'模式初始化
history.transitionTo(
history.getCurrentLocation(),
setupHashListener,
setupHashListener
)
}
// 添加监听
history.listen(route => {
this.apps.forEach((app) => {
app._route = route
})
})
}
}
自此,基本完成了对mode字段的前期校验和后期使用,history的实例也已经初始化完成。接下来就是路由的一些基本操作,比如push(),replace(),onReady()等。接着以上源码往下看,以下代码只留存关键行
onReady (cb: Function, errorCb?: Function) {
this.history.onReady(cb, errorCb)
}
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
// this.history会经过初始化操作,这里就会调用原生history的push方法
this.history.push(location, resolve, reject)
// this.history.push(location, onComplete, onAbort)
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
// replace也是原生方法的调用
this.history.replace(location, resolve, reject)
// this.history.replace(location, onComplete, onAbort)
}
从以上代码可看出,VueRouter类中的方法可以认为是一个代理,实际是调用的具体history对象的对应方法, 在init()方法中初始化时,会根据history对象具体的类别执行不同的操作。
说了这么多,什么时候调以及如何调用HTML5History和HashHistory有了大致的了解,后续再看这两个类是怎么实现的。