# 路由映射表与动态路由

# createMatcher

我们在使用 Vue-Router 的时候,需要创建 VueRouter 实例,并传入配置。之后再将这个 VueRouter 实例传入 Vue 根实例中。

const router = new VueRouter({
    mode:'hash',
    base:'',
    routes:[]
})

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

在创建 VueRouter 时,比较重要的一个属性就是 matcher(匹配器),通过 createMatcher 来创建的。

    this.app = null
    this.apps = []
    this.options = options
    this.beforeHooks = []
    this.resolveHooks = []
    this.afterHooks = []
    this.matcher = createMatcher(options.routes || [], this)

createMatcher :

// 创建匹配器

import createRouteMap from "./create-router-map";

export default function createMatcher(routes) {

    // 创建映射表
    let { pathMap } = createRouteMap(routes)


    /**
     * 
     * @param {Array} routes 动态添加多个路由
     */
    function addRoutes(routes) {
        createRouteMap(routes, pathMap)
    }

    /**
     * 
     * @param {object} route 动态添加一个路由
     */
    function addRoute(route) {
        createRouteMap([route], pathMap)
    }

    /**
     * 根据路由路径,返回对应的路由对象
     * @param {string} url 路由的路径
     * @returns object
     */
    function match(url) {
        return pathMap[url]
    }

    return {
        addRoutes,
        addRoute,
        match
    }
}

# 路由映射表

在创建匹配器时,第一步也是最重要的一步,就是创建路由映射表。在我们定义路由时,传入的是树状的数组,但是树状数组十分难操作,无论是后面动态添加路由,还是根据地址匹配路由,都很浪费性能。所以,Vue-Router 会将传入的数组扁平化,将路由路径作为映射表的 key,对应的路由对象作为映射表的 value

// 创建路由映射表

/**
 * 构建路由信息映射表
 * @param {Array} routes 路由信息
 * @param {Array} pathMap 已有的路由映射表,可选
 */
export default function createRouteMap(routes, pathMap = {}) {

    routes.forEach(route => {
        addRouteRecord(route, pathMap)
    })

    return { pathMap }
}

/**
 * 
 * @param {object} route 具体某个路由信息对象
 * @param {object} pathMap 映射表
 * @param {object} parentRecord 父路由信息对象
 */
function addRouteRecord(route, pathMap, parentRecord) {
    let path = route.path
    // 拼接路径
    if (parentRecord?.path) {
        path = parentRecord.path === '/' ? `/${route.path}` : `${parentRecord.path}/${route.path}`
    }
    let record = {
        path,
        component: route.component,
        props: route.props,
        meta: route.meta,
        name: route.name
    }
    // 路径 对应 路由信息 
    // 如果路径相同,后面的路由会覆盖前面的路由
    pathMap[path] = record

    // 递归处理子节点
    if (route.children) {
        route.children.forEach(cld => {
            addRouteRecord(cld, pathMap, record)
        })
    }
}

# 动态路由

在做到权限管理类的项目时,时常需要用到动态路由。在某些情况下,我们需要动态的向路由表中添加路由,这就用到了 Vue-Router 中的 addRoutes / addRoute API 。

    /**
     * 动态添加多个路由
     * @param {Array} routes 要动态添加多个路由数组
     */
    function addRoutes(routes) {
        createRouteMap(routes, pathMap)
    }

    /**
     * 动态添加一个路由
     * @param {object} route 要动态添加一个路由
     */
    function addRoute(route) {
        createRouteMap([route], pathMap)

    }

    /**
     * 根据路由路径,返回对应的路由对象
     * @param {string} url 路由的路径
     * @returns object
     */
    function match(url) {
        return pathMap[url]
    }

可以看到, addRoutes / addRoute 的底层其实就是将动态添加的路由以及当前已有的路由映射表 pathMap 传入 createRouteMap 函数,进而将新传入的路由解析到已有的路由映射表中。