写点什么

【VueRouter 源码学习】第六篇 - 路由匹配的实现

用户头像
Brave
关注
发布于: 2021 年 09 月 08 日
【VueRouter 源码学习】第六篇 - 路由匹配的实现

一,前言


上篇,介绍了两种路由模式的设计及初始化操作,主要涉及以下内容:


  • 创建两种路由模式类;

  • 父类和子类继承方法的设计;

  • 路由初始化 init 处理逻辑;


本篇,介绍路由匹配的实现;



二,承上启下

1,前文回顾


  • 执行 Vue.use 安装插件时,通过 Vue.mixin 向所有组件混入导出的 router 实例;

  • 将根组件上的 router 实例保存到_routerRoot上,使所有组件都能够通过父亲获取到根组件,即可以访问到同一个 router 实例;

  • 在 VueRouter 实例化时,通过路由匹配器 createMatcher 对路由配置进行扁平化处理;

  • 在路由匹配器中,创建了路由插件的两个核心方法:match 和 addRoutes;

  • 在 VueRouter 中创建了 history,存储不同模式下的子类逻辑的实现;

  • 在路由初始化时,会默认执行一次路由跳转 transitionTo 并在此时绑定路由变化的监听器,之后,当 Hash 再次变化时,将继续进行调跳转操作;

2,本篇介绍


所以,接下来就需要在跳转方法 transitionTo 中,根据当前路径获取到路由匹配的结果;



三,路由匹配的分析


前面,通过路由匹配器对路由配置进行了扁平化处理,示例:


// todo 添加 array -> obj 示例


{'/': Record1, '/user': Record2, '/user/info': Record3 }
复制代码


接下来,进行路由匹配,如果访问的路径是:/user/info,那么路由匹配的结果将是两条记录:


// 先匹配到 /user 之后,才能匹配到 /user/info;matches:[Record2, Record3]
复制代码


所以,一个路径可能命中多个路由匹配规则;


备注:路由匹配后返回的 matches 数组中,匹配到的多条记录将用于后续 <router-view> 的组件渲染;


四,路由匹配的实现

1,首次路由匹配


当页面加载完毕,路由进行初始化流程进入 init 方法,会默认触发一次路由跳转 transitionTo;

此时需要进行一次路由匹配操作,即:根据当前页面路径 location 到 router 实例上的 matcher 中做匹配;


// history/base.js
/** * 路由基类 */class History { constructor(router) { this.router = router; }
/** * 路由跳转方法: * 每次跳转时都需要知道 from 和 to * 响应式数据:当路径变化时,视图刷新 * @param {*}} location * @param {*} onComplete */ transitionTo(location, onComplete) { // 根据路径进行路由匹配 let route = this.router.match(location); onComplete && onComplete(); }}
export { History }
复制代码

2,router.match 的实现


在 VueRouter 类中添加 match 方法,提供路由跳转时调用:

/** * 根据路径匹配到路由映射表 matcher 中进行路由匹配 * 备注:VueRouter 类通过 match 方法对外提供 matcher 的访问,而不是直接访问 matcher * @param {*} location 路径 * @returns 匹配结果数组 */match(location) {    // createMatcher.match    return this.matcher.match(location);}
复制代码


备注:根据类的封装性设计原则,在 History 类方法中,不能直接 访问 VueRouter 类中的实例属性 matcher,需要通过类方法 match 方法对方提供数据访问;


3,matcher.match 的实现


路由匹配器 createMatcher 中 match 方法的实现:

import createRouteMap from "./create-route-map"import { createRoute } from './history/base'
/** * 路由匹配器 * 路由配置扁平化处理 * 核心方法:addRoutes、match * @param {*} routes * @returns */export default function createMatcher(routes) {
// 路由配置扁平化处理 let { pathMap } = createRouteMap(routes);
/** * 动态添加路由配置 * @param {*} routes */ function addRoutes(routes) { createRouteMap(routes, pathMap); } /** * 根据路径进行路由匹配 * @param {*} location 路径 * @returns 路由匹配的全部结果 */ function match(location) { // 获取路由记录 let record = pathMap[location]; // 一个路径可能有多个记录 // 匹配成功 if (record) { return createRoute(record, { path: location }) } // 未匹配到 return createRoute(null, { path: location }) }
return { addRoutes, // 添加路由 match // 用于匹配路径 }}
复制代码

4,createRoute 实现


let record = pathMap[location]匹配一条路由记录;

需要将路由记录拆分,并逐层进行路由匹配,通过 createRoute 得到匹配记录数组:

// history/base.js
/** * 通过路由记录,逐层进行路由匹配 * @param {*} record 路由记录 * @param {*} location 路径 * @returns 逐层匹配后的全部匹配结果 */export function createRoute(record, location) { let res = []; //[/user /user/info] if (record) { while (record) { res.unshift(record); record = record.parent; } } return { ...location, matched: res }}
class History { constructor(router) { this.router = router; // {'/': Record1, '/user': Record2, '/user/info': Record3 } this.current = createRoute(null, { path: '/' }); }
/** * 路由跳转方法: * 每次跳转时都需要知道 from 和 to * 响应式数据:当路径变化时,视图刷新 * @param {*}} location * @param {*} onComplete */ transitionTo(location, onComplete) { // 根据路径进行路由匹配 let route = this.router.match(location); onComplete && onComplete(); }}
export { History }
复制代码



五,结尾


本篇,介绍路由匹配的实现,包括以下几个点:


  • 路由匹配的分析;

  • 路由匹配的实现:router.match、matcher.match、createRoute;


下一篇,路由变化触发视图更新;

用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【VueRouter 源码学习】第六篇 - 路由匹配的实现