vue-router
const router = new VueRouter({ routes })
Vue.use(VueRouter)
new Vue({ router })
实例化VueRouter
// 传入路由表
[
{
path: '/demo',
components: {
default: Default,
name1: Name1,
},
children: [{}...],
// 守卫
}
]
1. this.matcher = createMatcher(options.routes || [], this) 构建record树
const record: RouteRecord = {
// 当前路由对应的路径
path,
// 当前路由渲染的组件对象
components: { default: route.component },
// 当前这条路由对应的组件实例
instances: {},
enteredCbs: {},
// 父路由
parent,
redirect: route.redirect,
// 守卫钩子
beforeEnter: route.beforeEnter,
}
match方法: 根据当前url匹配所有相关路由
2. 全局守卫
this.beforeHooks = []
this.resolveHooks = []
this.afterHooks = []
3. this.history = new HTML5History(this, options.base)
this.current = START // 一条route
route: Route = {
path: location.path || '/',
hash: location.hash || '',
// 参数
query,
params: location.params,
fullPath,
// 很重要,由父到子的路由record
matched: record ? formatMatch(record) : []
}
record概念:根据路由表创建 (路径对应组件)
route概念: 根据当前url创建(path query params matched)
Vue.use(VueRouter) 注册插件 执行插件的install方法
// 通过mixin方法混入 beforeCreate 钩子:
// 根组件时执行
this._routerRoot = this
// VueRouter实例(matcher history)
this._router = this.$options.router
// 初始化操作
this._router.init(this)
// 响应式_route,后面更改的时候触发重新渲染
Vue.util.defineReactive(this, '_route', this._router.history.current)
// Vue原型上定义
$router this._routerRoot._router 为了提供 push replace 等方法
$route this._routerRoot._route 为了获得当前路由相关的信息 (params query等)
// 注册组件
RouterView RouterLink
router.init
history.transitionTo(最新的url, cb1)
// 根据url 获取route,值得注意的是属性matched: [父record,子record]
// 守卫
confirmTransition(route, cb2) // 根据route 和 current 得到 deactivated activated updated
1.extractLeaveGuards(deactivated) // 失活组件的 beforeRouteLeave
2.router.beforeHooks // 所有的失活组件已离开,即将进入更新
3.extractUpdateHooks(updated) // 更新组件的钩子
4.activated.map(m => m.beforeEnter) // 即将enter的组件的配置钩子
5.resolveAsyncComponents(activated) // 即将enter的组件, 看下是否是异步组件(异步next)
6.extractEnterGuards(activated) // 组件enter钩子(注意: enter的组件获取不到实例)next(ins => {})
7.router.resolveHooks // resolveHooks
// runQueue
执行每个钩子函数,传入 route(路由信息) , current, next方法
调用next才会step向下 next() next(false) next(newPath)
8.this.current = route //此时浏览器url还未更新
9.window.addEventListener('popstate', handleRoutingEvent: 执行transitionTo)
10.this.ensureURL() // 更改url 如果不是初次渲染,这个时候开始更新组件
11.router.afterHooks // 守卫结束
12.history.listen // 监听路由变化
RouterView
/*
在生成 <router-view></router-view> vnode的时候,发现组件配置 functional 为true
执行组件配置的render方法
*/
render(_, { props /* name该路由对应的组件,默认default */, children, parent/* 父vm */, data }) {
const name = props.name || 'default'
const route = parent.$route
data.routerView = true
// 遍历所有parent组件
if (vnodeData.routerView) {
depth++
}
const matched = route.matched[depth]
const component = matched && matched.components[name]
// 返回对应的组件vnode
h(component, data, children)
}