@wy
2020-06-02T02:26:11.000000Z
字数 3056
阅读 667
源码解析
进入到 index.js 中来看在 new VueRouter 时做了哪些事。
先大致看一遍挂在类上的属性和方法,不用一上来就弄明白每个函数内部的实现,可以结合官方文档去看这些方法的用处,先有个印象。函数体代码太长,可以先折叠起来。
要掌握看代码的套路根据调用方式,从入口处着手,在脑海中运行程序,分析每进行一步运行后产生的结果,遇到函数调用或者分支条件,可以先忽略。
定义一个 VueRouter 的类,用 new 调用时, constructor 构造函数执行。在构造函数中通常会初始化一些值,留作日后访问。
class VueRouter {// .... 其他忽略constructor (options: RouterOptions = {}) {this.app = nullthis.apps = []this.options = optionsthis.beforeHooks = [];this.resolveHooks = []this.afterHooks = []this.matcher = createMatcher(options.routes || [], this)let mode = options.mode || 'hash'this.fallback = mode === 'history' && !supportsPushState && options.fallback !== falseif (this.fallback) {mode = 'hash'}if (!inBrowser) {mode = 'abstract'}this.mode = modeswitch (mode) {case 'history':this.history = new HTML5History(this, options.base)breakcase 'hash':this.history = new HashHistory(this, options.base, this.fallback)breakcase 'abstract':this.history = new AbstractHistory(this, options.base)breakdefault:if (process.env.NODE_ENV !== 'production') {assert(false, `invalid mode: ${mode}`)}}}}
初始化时通过 options 接收参数,称之为路由配置对象,由调用者提供:
new VueRouter({ // 路由配置对象mode: 'history',base: '/app',routes: [{path: '',component: '',name: '',}]// ... 其他配合})
构造函数中主要做了三件事:
在得到路由实例后,可以使用提供的全局钩子函数,例如:
let router = new VueRouter({})router.beforeEach(() => { // 注册函数})router.beforeEach(() => { // 注册函数})router.beforeResolve(() => { // 注册函数})router.afterEach(() => { // 注册函数})
如果你愿意,可以给调用同一个钩子函数注册多个函数。这些注册的函数,未来需要按照注册顺序依次执行,就需要把注册的函数存放在一个地方,那就是上面分别定义的 **.hooks 数组中。
在 index.js 中找到这三个函数,定义在类中,作为原型上的方法:
class VueRouter {... 其余省略代码beforeEach (fn: Function): Function {return registerHook(this.beforeHooks, fn)}beforeResolve (fn: Function): Function {return registerHook(this.resolveHooks, fn)}afterEach (fn: Function): Function {return registerHook(this.afterHooks, fn)}}
这里三个函数做的动作是一样的,都是向数组中添加注册的函数,所以抽成了函数 registerHook 处理。
再看 registerHooks 函数实现,很简单:
function registerHook (list: Array<any>, fn: Function): Function {list.push(fn)return () => {const i = list.indexOf(fn)if (i > -1) list.splice(i, 1)}}
作用:接收一个数组和函数,把函数存在指定的数组中。
registerHook 执行结束后,返回一个函数。返回的函数作用是调用后,把注册的函数从数组中移除,这里很巧妙的用了闭包。
也就是说调用 beforeEach 后,返回一个函数,调用返回的函数后,可以取消注册函数。
let router = new VueRouter({})let cancel = router.beforeEach(() => { // 注册函数// 此钩子函数被取消,不在执行。})cancel();
至于多个钩子函数是怎么按照顺序执行的,后面会详细分析。
createMatcher 函数所在文件是 create-matcher.js,中,查看完整代码:;
先来看下如何使用,在 index.js 中:
class VueRouter {constructor(options){this.matcher = createMatcher(options.routes || [], this);}}new VueRouter({mode: 'history',routes: [{path: '/', component: Home},{name: 'about', component: About}]})
从代码中可以看出来,createMatcher 接受两个参数:
- routes,路由配置对象中,路径和组件映射信息
- this,为路由对象
来到 create-matcher.js 文件中,简化后代码:
```
// ... 引入一堆所需文件
export function createMatcher(routes, router){
const { pathList, pathMap, nameMap } = createRouteMap(routes)
function addRoutes (routes) {
createRouteMap(routes, pathList, pathMap, nameMap)
}
function match(){/代码省略/}
function redirect(){/代码省略/}
function alias(){/代码省略/}
function _createRoute(){/代码省略/}
return {
match,
addRoutes
}
}
```ss