vue-router是vue官方支持,可以看做vue最佳实践
本文大致梳理vue-router源码各个文件大体作用,不深入细节
建议对照vue-router源码阅读
src/index.js
1. VueRouter类
-
构造器
-
createMatcher
分析路由配置、路径、层级等; - 根据
mode
、fallback
配置和浏览器history.pushState
支持情况创建对应的history
实例(push
、replace
、go
等方法,通过操作history
实现);
-
-
init
方法 - 暴露
addRoutes
、push
、replace
、go
等路由操作方法; - 暴露
beforeEach
、beforeResolve
、onReady
等钩子函数;
2. VueRouter
类添加install
方法
这个方法的第一个参数是 Vue
构造器,第二个参数是一个可选的选项对象(Vue插件);
src/install.js
VueRouter
类的install
方法
- 判断
Vue
是否已初始化Vue-router
; -
通过全局混入
Vue.mixin
实现注册和销毁,使用全局混入将影响每一个之后创建的 Vue 实例(Vue全局混入)。-
beforeCreate
中this
指向为Vue
组件实例,所有组件beforeCreate
声明周期都会调用此函数; -
this.$options.router
指new 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.$router
和this.$route
操作路由和获取当前路由信息。 - 声明全局组件
RouterView
和RouterLink
- 设置选项合并策略(自定义选项合并策略)
src/history/base.js
History
类,HashHistory
和HTML5History
都继承自这个基础类
- 定义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
全局组件RouterView
,functional
组件(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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。