一,前言
上篇,介绍路由插件 install 的实现,主要包含以下内容:
创建 vue-router 目录结构;
插件引入入口 index.js 逻辑实现;
插件安装入口 install.js 逻辑实现;
为所有组件混入 router 实例;
本篇,创建路由映射表;
二,承上启下
1,前文回顾
完成了路由插件的配置、注册,并导出 router 路由实例;
在 Vue 初始化时,将 router 路由实例注册到了 Vue 实例上(即根组件 Vue.app);
自建 vue-router 插件目录结构:导入入口 index.js,安装逻辑 install.js;
执行 Vue.use 安装插件时,通过 Vue.mixin 向所有组件混入导出的 router 实例;
备注:在组件创建前,通过全局混入 beforeCreate 生命周期函数,将 router 实例从根组件逐层地共享给其他子组件;
至此,完成了插件的创建:创建了插件导入入口和 install 安装方法;
2,本篇介绍
但是,目前还只是一个插件的“空壳”,引入插件后并没有进行插件功能的初始化;
所以,需要在插件安装时执行的 install 方法中,完成插件的初始化操作;
路由插件初始化的主要逻辑如下:
在 VueRouter 实例化时,接收外部传入的路由配置 options:new Router(options)
,构造函数内部通过 createMatcher 路由匹配器对其进行处理;
在路由匹配器 createMatcher 中,将路由配置处理为便于匹配的扁平化结构对象 matcher;
在路由匹配器中创建路由插件的两个核心方法:match 和 addRoutes;
在 VueRouter 类中,创建路由初始化方法 init,当执行Vue.use
安装路由插件在 install 方法中处理根组件时,执行路由的 init 初始化操作,将根实例 Vue.app 传入 init 方法中;
三,路由插件的初始化
1,路由实例化时的初始化逻辑
new VueRouter
进行路由的初始化时,在构造函数中需要完成以下几件事:
创建路由匹配器 createMatcher 处理路由配置:将嵌套数组处理为扁平对象,便于路由匹配操作;
创建 match 方法,用于通过路由规则匹配到对应的组件;
创建 addRoutes 方法,用于动态的添加路由匹配规则;
2,路由安装时的初始化逻辑 init
// index.js
import install from './install'
class VueRouter {
constructor(options) { // 传入配置对象 options
}
// 路由初始化方法,供 install 安装时调用
init(app) {
}
}
VueRouter.install = install;
export default VueRouter;
复制代码
在根组件中,调用路由实例上的 init 方法,完成插件的初始化:
// install.js
export let _Vue;
/**
* 插件安装入口 install 逻辑
* @param {*} Vue Vue 的构造函数
* @param {*} options 插件的选项
*/
export default function install(Vue, options) {
_Vue = Vue;// 抛出 Vue 供其他文件使用
// 混入:所有组件都能够通过 this._routerRoot._router 获取到同一个 router 实例;
Vue.mixin({
beforeCreate() {
if (this.$options.router) {// 根组件
this._routerRoot = this;
this._router = this.$options.router;
// 在根组件中,调用路由实例上的 init 方法,完成插件的初始化
this._router.init(this); // this 为根实例
} else { // 子组件
this._routerRoot = this.$parent && this.$parent._routerRoot;
}
}
});
}
复制代码
四,路由匹配器函数 createMatcher
1,创建路由匹配器函数
新建 create-match.js 文件,创建路由匹配器函数 createMatcher:
// create-match.js
/**
* 路由匹配器函数
* 对路由配置进行扁平化处理
* addRoutes:动态添加路由匹配规则
* match:根据路径进行路由匹配
* @param {*} routes
* @returns 返回路由匹配器的两个核心方法 addRoutes、match
*/
export default function createMatcher(routes) {
// 将嵌套数组的路由配置,处理为便于匹配的扁平结构
// 创建 match 方法:根据路径进行路由匹配
// 创建 addRoutes 方法:动态添加路由匹配规则
}
复制代码
VueRouter 构造函数中,使用路由匹配器函数 createMatcher,将嵌套数组类型的路由配置进行扁平化处理:
// index.js
import install from './install'
import createMatcher from './create-matcher'; // 导入匹配器
class VueRouter {
constructor(options) {
// 路由匹配器-处理路由配置:将树形结构的嵌套数组转化为扁平化结构的对象,便于后续的路由匹配
// 路由匹配器返回两个核心方法:match、addRoutes
this.matcher = createMatcher(options.routes || []);// options.routes 默认[]
}
/**
* 路由初始化方法,供 install 安装时调用
* @param {*} app 根组件实例(在处理根组件时被调用)
*/
init(app) {
}
}
VueRouter.install = install;
export default VueRouter;
复制代码
处理完成后,路由实例上的 matcher 属性,将存储扁平化结构的全部路由匹配规则,用于后续路由匹配操作;
2,路由配置的扁平化处理
在 create-route-map.js 文件中,处理路由配置:
// create-route-map.js
/**
* 路由配置扁平化处理
* 支持初始化和追加两种情况
* @param {*} routes 路由实例中的路由配置
* @param {*} oldPathMap 路由规则映射表(扁平化结构)
* @returns 新的路由规则映射表(扁平化结构)
*/
export default function createRouteMap(routes, oldPathMap){
// 拿到当前已有的映射关系
let pathMap = oldPathMap || Object.create(null);
// 将路由配置 routes 依次加入到 pathMap 路由规则的扁平化映射表
routes.forEach(route => {
addRouteRecord(route, pathMap);
});
return {
pathMap
}
}
/**
* 添加一个路由记录(递归当前的树形路由配置)
* 先序深度遍历:先把当前路由放进去,再处理他的子路由
* @param {*} route 原始路由记录
* @param {*} pathMap 路由规则的扁平化映射表
* @param {*} parent 当前路由所属的父路由对象
*/
function addRouteRecord(route, pathMap, parent){
// 处理子路由时,需要做路径拼接
let path = parent ? (parent.path + '/' + route.path) : route.path
// 构造路由记录对象(还包含其他属性:path、component、parent、name、props、meta、redirect...)
let record = {
path,
component: route.component,
parent // 标识当前组件的父路由记录对象
}
// 查重:路由定义不能重复,否则仅第一个生效
if (!pathMap[path]) {
pathMap[path] = record; // 将当前路由的映射关系存入pathMap
}
// 递归处理当前路由的子路由
if (route.children) {
route.children.forEach(childRoute => {
addRouteRecord(childRoute, pathMap, record);
})
}
}
复制代码
在路由匹配器中,调用 createRouteMap 方法,进行路由配置的扁平化处理:
import createRouteMap from "./create-route-map"
export default function createMatcher(routes) {
// 路由配置的扁平化处理
let { pathMap } = createRouteMap(routes);
}
复制代码
3,添加 match 方法
创建 match 方法,用于通过路由规则匹配到对应的组件;
import createRouteMap from "./create-route-map"
export default function createMatcher(routes) {
// 路由配置的扁平化处理
let { pathMap } = createRouteMap(routes);
// 根据路径进行路由匹配
function match(location) {
let record = pathMap[location];
}
return {
addRoutes, // 添加路由
match // 用于匹配路径
}
}
复制代码
4,添加 addRoutes 方法
创建 addRoutes 方法,用于动态的添加路由匹配规则;
import createRouteMap from "./create-route-map"
export default function createMatcher(routes) {
// 路由配置的扁平化处理
let { pathMap } = createRouteMap(routes);
// 根据路径进行路由匹配
function match(location) {
let record = pathMap[location];
}
/**
* 动态添加路由匹配规则
* 将追加的路由规则进行扁平化处理
*/
function addRoutes(routes) {
createRouteMap(routes,pathMap);
}
return {
addRoutes, // 添加路由
match // 用于匹配路径
}
}
复制代码
应用场景:在后台管理应用中,部分菜单/路由是根据权限配置来决定的,可以使用路由插件提供的 addRoutes 方法动态添加路由;
五,结尾
本篇,介绍了路由映射表的创建,主要包含以下内容:
下一篇,介绍路由跳转的实现;
评论