VueRouter 构造函数
class VueRouter {
constructor(options) {
// 1.接收 RouterOptions
// routes 是路由配置表,是一个数组,每一项都是一个路由配置规则;
// mode、fallback 是跟路由模式相关的;
// 2.创建匹配器的过程,并返回 match, addRoutes 方法
// match函数:匹配功能
// addRoutes函数:可以添加匹配,动态路由添加
this.matcher = createMatcher(options.routes || []);
// 3.创建路由模式,默认值是 hash 模式
this.mode = options.mode || 'hash';
switch (this.mode) {
case 'hash':
this.history = new HashHistory(this)
break;
case 'history':
this.history = new BrowserHistory(this);
break;
}
// 4.初始化钩子队列(这里只初始化 beforeHooks)
this.beforeHooks = [];
}
match(location) {
}
init(app) {
}
push(location) {
}
beforeEach(fn) {
}
}
创建匹配器
JavaScript
JavaScript
import createRouteMap from './create-route-map'
import { createRoute } from './history/base'
export default function createMatcher(routes) {
// 动态添加路由 规则就是 404 首页 所有人都能看到 先配好了
// 登录了 => 再将对应的权限和之前的进行一个组合 (菜单全选 路由权限)
// routes 是用户自己配置的,但是用起来不方便,利用 createRouteMap 生成 pathList、pathMap
// pathList:把所有的路由t,组成一个数组 => ['/', '/about', '/about/a', '/about/b', '/xxx']
// pathMap :把所有的路由,组成一个map => { '/': { }, '/about': { }, '/about/a': { } }
let { pathList, pathMap } = createRouteMap(routes);
// 通过用户输入路径,获取对应的匹配记录
function match(location) {
let record = pathMap[location];// 获取对应的记录
// /about/a => matched:[/about,/a]
return createRoute(record, { path: location })
}
// 动态格式化路由
function addRoutes(routes) {
// routes 动态添加的路由
createRouteMap(routes, pathList, pathMap)
}
return { match, addRoutes };
}
const addRouteRecord = (route, pathList, pathMap, parentRecord) => {
// 多层级路由时,做拼接
let path = parentRecord ? `${parentRecord.path}/${route.path}` : route.path;
// 根据当前路由产生一个记录 path/component
let record = { path, component: route.component, parent: parentRecord /* 记录父路径 */ };
// 防止用户编写路由时有重复的,不去覆盖
if (!pathMap[path]) {
pathMap[path] = record;
pathList.push(path);
}
/// 要将子路由也放到对应的 pathMap 和 pathList
if (route.children) {
route.children.forEach(r => {
addRouteRecord(r, pathList, pathMap, record);
});
}
}
// 具备初始化和新增的功能
function createRouteMap(routes, oldPathList, oldPathMap) {
let pathList = oldPathList || [];
let pathMap = oldPathMap || {};
routes.forEach(route => { addRouteRecord(route, pathList, pathMap) });
return { pathList, pathMap };
}
export default createRouteMap;
路由模式
JavaScript
JavaScript
// 根据匹配到的记录来计算匹配到的所有的记录
export const createRoute = (record, location) => {
let matched = []
if (record) {
while (record) {
matched.unshift(record);
record = record.parent; // 通过当前记录找到所有的父亲
}
}
// {path:'/',matched:[{}]}
return { ...location, matched };
}
const runQueue = (queue, iterator, complete) => {
function next(index) {
if (index >= queue.length) {
return complete();
}
let hook = queue[index]; // 取出hook钩子函数
iterator(hook, () => next(index + 1)); // 就是遍历的过程
}
next(0);
}
// 这个 current 就是一个普通的变量,希望 current 变化了可以更新视图
export default class History {
constructor(router) {
this.router = router;
// 这个代表的是,当前路径匹配出来的记录
// /about/a 匹配=> {path:'/about',component:about}、{path:'/about/A',component:A}
// this.current = {path:'/',matched:[]}
this.current = createRoute(null, { path: '/' }); // 默认值
}
transitionTo(location, complete) {
// 获取当前路径匹配出对应的记录,当路径变化时获取对应的记录 => 渲染页面 (router-view实现的)
// 通过路径拿到对应的记录,有了记录之后,就可以找到对象的匹配
// 当路径变化后 current 属性会进行更新操作
let current = this.router.match(location);
// 防止重复点击 不需要再次渲染
// 匹配到的个数和路径都是相同的,就不需要再次跳转了
if (this.current.path == location && this.current.matched.length === current.matched.length) {
return;
}
let queue = this.router.beforeHooks; // 钩子函数队列
const iterator = (hook, next) => { hook(current, this.current, next) };
runQueue(queue, iterator, () => {
this.current = current; // 这个 current 只是响应式的,他的变化不会更新 _route
this.cb && this.cb(current); // 手动更新 _route 的回调函数
complete && complete(); // 监听浏览器 url 变化的事件的初始化函数
});
}
listen(cb) { // 保存回调函数
this.cb = cb;
}
}
import History from './base';
const ensureSlash = () => {
// window.location.href.slice('#')[1]
if (window.location.hash) {
return;
}
window.location.hash = '/';
}
export default class HashHistory extends History {
constructor(router) {
super(router);
this.router = router;
ensureSlash(); // 如果没有 hash 值,应该跳转到 首页 #/
}
getCurrentLocation() {
return window.location.hash.slice(1);
}
setupListener() {
window.addEventListener('hashchange', () => {
// 再次执行匹配操作
this.transitionTo(this.getCurrentLocation())
})
}
}
打赏作者
您的打赏是我前进的动力
微信
支付宝
安装插件
上一篇
评论