这是对vue-router 3 版本的源码分析。
本次分析会按以下方法进行:
本章讲解router中嵌套路由是如何实现的。
另外我的vuex3源码分析也发布完了,欢迎大家学习:
vuex3 最全面最透彻的源码分析
还有vue-router的源码分析:
vue-router 源码分析——1. 路由匹配
vue-router 源码分析——2. router-link 组件是如何实现导航的
vue-router 源码分析——3. 动态路由匹配
vue-router 源码分析——4.嵌套路由
// 创建的 app
<div id="app">
<router-view></router-view>
</div>
const User = {
template: `
User {{ $route.params.id }}
`
}
const router = new VueRouter({
routes: [
{
path: '/user/:id',
component: User,
children: [
{
// 当 /user/:id/profile 匹配成功,
// UserProfile 会被渲染在 User 的 中
path: 'profile',
component: UserProfile
},
{
// 当 /user/:id/posts 匹配成功
// UserPosts 会被渲染在 User 的 中
path: 'posts',
component: UserPosts
}
]
}
]
})
// create-route-map.js
function addRouteRecord(
pathList: Array<string>,
pathMap: Dictionary<RouteRecord>,
nameMap: Dictionary<RouteRecord>,
route: RouteConfig,
parent?: RouteRecord,
matchAs?: string
) {
const { path, name } = route
const normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict)
const record: RouteRecord = {
path: normalizedPath,
components: route.components || { default: route.component},
parent,
...
}
if (route.children) {
...
route.children.forEach(child => {
// 递归调用 addRouteRecord,将父record加入到子record的parent中
addRouteRecord(pathList, pathMap, nameMap, child, record, undefined)
})
}
}
// ./util/route.js
export function createRoute(
record: ?RouteRecord,
location: Location,
redirectedFrom?: ?Location,
router?: VueRouter
): Route {
const route: Route = {
path: location.path || '/',
params: location.params || {},
matched: record ? formatMatch(record) : [],
...
}
...
return Object.freeze(route)
}
function formatMatch(record: ?RouteRecord): Array<RouteRecord> {
const res = []
while (record) {
res.unshift(record)
record = record.parent
}
return res
}
// ./components/view.js
export default {
...
render(_, { props, children, parent, data }) {
data.routerView = true
const h = parent.$createElement
const route = parent.$route
let depth = 0
while (parent && parent._routerRoot !== parent) {
const vnodeData = parent.$vnode ? parent.$vnode.data : {}
// 如果父节点也是router-view,则深度+1
if (vnodeData.routerView) {
depth++
}
parent = parent.$parent
}
data.routerViewDepth = depth
// 取出对应深度的 matched和component 作为当前url对应路由的渲染数据
const matched = route.matched[depth]
const component = matched && matched.components[name]
if (!matched || !component) {
return h()
}
...
return h(component, data, children)
}
}