写点什么

【VueRouter 源码学习】第四篇 - 创建路由映射表

用户头像
Brave
关注
发布于: 5 小时前
【VueRouter 源码学习】第四篇 - 创建路由映射表

一,前言


上篇,介绍路由插件 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 方法动态添加路由;


五,结尾


本篇,介绍了路由映射表的创建,主要包含以下内容:


  • 路由安装的初始化:init 方法;

  • 路由初始化:constructor 构造函数逻辑;

  • 创建路由匹配器:createMatcher;

  • match 方法 和 addRoutes 方法的实现;


下一篇,介绍路由跳转的实现;

用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【VueRouter 源码学习】第四篇 - 创建路由映射表