一,前言
上篇,介绍了两种路由模式的设计及初始化操作,主要涉及以下内容:
创建两种路由模式类;
父类和子类继承方法的设计;
路由初始化 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 }
复制代码
五,结尾
本篇,介绍路由匹配的实现,包括以下几个点:
下一篇,路由变化触发视图更新;
评论