vue-router是vue官方支持,可以看做vue最佳实践
本文大致梳理vue-router源码各个文件大体作用,不深入细节
建议对照vue-router源码阅读

src/index.js

1. VueRouter类
  • 构造器

    • createMatcher分析路由配置、路径、层级等;
    • 根据modefallback配置和浏览器history.pushState支持情况创建对应的history实例(pushreplacego等方法,通过操作history实现);
  • init方法
  • 暴露addRoutespushreplacego等路由操作方法;
  • 暴露beforeEachbeforeResolveonReady等钩子函数;
2. VueRouter类添加install方法

这个方法的第一个参数是 Vue构造器,第二个参数是一个可选的选项对象(Vue插件);

src/install.js

VueRouter类的install方法

  • 判断Vue是否已初始化Vue-router;
  • 通过全局混入Vue.mixin实现注册和销毁,使用全局混入将影响每一个之后创建的 Vue 实例(Vue全局混入)。

    • beforeCreatethis指向为Vue组件实例,所有组件beforeCreate声明周期都会调用此函数;
    • this.$options.routernew Vue时传入的Vue-router实例,this.$options.router不为空,说明此时this指向Vue根组件实例;
    new Vue({
      router,// this.$options.router不为空,说明此时this指向Vue根组件实例
      render: h => h(App)
    }).$mount('#app')
    • this._routerRoot指向Vue根组件实例,后续所有子组件实例的_routerRoot均指向this.$parent._routerRoot,所有子组件的_routerRoot通过层层传递的形式指向根组件实例;
  • 添加 Vue 实例属性$router$route,通过把它们添加到 Vue.prototype 上实现。这里通过Object.defineProperty只设置了get方法,是为了防修改。这样所有组件可通过this.$routerthis.$route操作路由和获取当前路由信息。
  • 声明全局组件RouterViewRouterLink
  • 设置选项合并策略(自定义选项合并策略

src/history/base.js

History类,HashHistoryHTML5History都继承自这个基础类

  • 定义go、push、replace、ensureURL、getCurrentLocation方法,由子类实现
  • 构造器,初始化属性,处理<base>标签

src/components/link.js

全局组件RouterLink

默认渲染为<a>标签

tag: {
    type: String,
    default: 'a'
}

默认事件为click

事件回调handler先通过guardEvent过滤掉部分事件,然后进行跳转

const handler = e => {
  if (guardEvent(e)) {
    if (this.replace) {
        router.replace(location, noop)
    } else {
        router.push(location, noop)
    }
  }
}

tag属性为a,则事件直接绑定到组件上

if (this.tag === 'a') {
  data.on = on
}

修改tag,则先查找default插槽(Vue具名插槽)中是否有<a>标签,有则绑定到最先找到的<a>标签上,没有找到则直接绑定到组件上

if (this.tag === 'a') {
    ...
} else {
    // find the first <a> child and apply listener and href
    const a = findAnchor(this.$slots.default)
    if (a) {
        // append new listeners for router-link
        ...
    } else {
        // doesn't have <a> child, apply listener to self
        data.on = on
    }
}

src/components/view.js

全局组件RouterViewfunctional组件(Vue函数式组件)。

  • 标记routerview,便于确认层级
// used by devtools to display a router-view badge
data.routerView = true
  • 值得注意的是,render函数没有使用自身的createElement方法,而是使用了父节点的parent.$createElement,备注说明大体意思是为了解析具名插槽
// directly use parent context's createElement() function
// so that components rendered by router-view can resolve named slots
const h = parent.$createElement
  • 确认路由层级,处理父组件keepAlive
// determine current view depth, also check to see if the tree
// has been toggled inactive but kept-alive.
let depth = 0
let inactive = false
// parent._routerRoot !== parent说明parent不是Vue根组件实例
// 参考src/install.js中beforeCreate方法
while (parent && parent._routerRoot !== parent) {
  const vnodeData = parent.$vnode ? parent.$vnode.data : {}
  if (vnodeData.routerView) {
    // 如果只是要确认路由层级,这里就可以depth = vnodeData.routerViewDepth + 1;break;了
    depth++
  }
  if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {
    inactive = true
  }
  parent = parent.$parent
}
data.routerViewDepth = depth

王恩智
171 声望3 粉丝

打杂的大龄90后