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