vue-router源码浅析
# vue router 源码浅析
# 概述
# 常用属性介绍
# RouterLink
RouterLink实际上就是通过 vue 的defineComponent方法定义的组件,创建一个<a>标签, 该组件内部会调用useLink()方法,这个useLink会根据参数 props 创建响应式的链接属性,以及处理链接事件
# RouterView
RouterView同上,也是 vue 的defineComponent定义的组件
# 常用 API 介绍
# createRouter
createRouter 方法用来创建一个路由实例,该方法接受一个参数,该参数是一个对象,该对象用来配置路由实例,通常如下创建
const router = createRouter({
history: createWebHashHistory(),
routes,
});
2
3
4
createRouter首先就会调用createRouterMatcher方法,返回的值标记为matcher
# createRouterMatch
createRouterMatch方法接受一个routes数组和全局配置,会返回addRoute、removeRoute、getRoutes、getRecordMatcher、resolve等方法。在其内部会遍历routes并调用addRoute
addRoute: 添加路由removeRoute: 移除路由getRoutes: 获取路由getRecordMatcher: 获取路由记录匹配器resolve:解析路由
createRouter方法创建的实例有以下属性
return {
currentRoute,
listening: true,
addRoute,
removeRoute,
hasRoute,
getRoutes,
resolve,
options,
push,
replace,
go: (step) => routerHistory.go(step),
back: () => go(-1),
forward: () => go(1),
beforeEach: beforeGuards.add,
beforeResolve: beforeResolveGuards.add,
afterEach: afterGuards.add,
onError: errorListeners.add,
isReady,
install,
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
go、back、forward方法本质上调用的都是options.history.go方法,而这个go方法本质上还是调用的window.history.go。addRoute方法:可以用于动态添加路由,接受两个参数,parentRouteName和route;若parentRouteName为空,则添加到根路由下,否则添加到指定路由下。其内部是调用的matcher的addRoute方法。removeRoute方法:接受一个参数name,用于删除指定路由。首先会调用matcher的getRecordMatcher方法,如果返回有值,则调用matcher的removeRoute方法。hasRoute方法:接受一个参数name,判断路由是否存在,调用matcher的getRecordMatcher方法getRoutes方法: 返回所有路由,遍历调用matcher的getRoutes方法的返回值,取其record
# createWebHistory
createWebHistory创建一个 history 模式路由, 返回一个 routerHistory 对象。该对象提供了以下方法:go、replace、push、listen、destory、pauselisten等方法以及location和state对象。
createWebHistory方法中主要用到了useHistoryStatenavigation和useHistoryListeners方法.
实现步骤: 1.接受一个参数
base,调用normalizeBase方法进行路由规范化处理,去除协议和域名部分,确保路由以/开头和不以/结尾 2.调用useHistoryStatenavigation方法,创建一个navigation对象,用于记录路由变化和状态 3.调用useHistoryListeners方法,创建一个listeners对象,用于记录路由变化监听器 4.赋值 2、3 的返回给routerHistory,并返回
# useHistoryStateNavigation
useHistoryStateNavigation方法首先会根据window.location和 base 获取当前的路由值, 然后判断window.history.state,如果其不为空则调用changeLocation在其内部调用window.history.replaceState或者window.history.pushState,最后改变 state 的值。
useHistoryStateNavigation方法返回的push和replace方法均会调用changeLocation方法,其中push会调用两次
# useHistoryListeners
useHistoryListeners方法接受四个参数base、调用useHistoryStateNavigation方法返回的state、location属性和replace方法
其内部实现主要逻辑是监听popstate和beforeunload事件,执行相应的路由切换逻辑,从而实现前端路由的控制和管理
popstate事件:浏览器的历史记录发生变化(用户的执行某些导航操作,如点击浏览器的前进、后退按钮或者通过 javascript 调用history.pushState、history.replaceState、history.back()和history.forward()等方法时会触发,触发popstate事件,vue router内部会执行popStateHandler函数,popStateHandler函数主要是判断state,如果state存在,则更新当前位置、历史状态并计算位置偏移值;如果state不存在,则调用replace方法更新。最后遍历了注册的所有监听器listeners并执行监听器, 传参为三个:currentLocation.value:当前位置信息、from:之前的位置信息、路由变化的对象:delta、type:'pop'、direction:正负表示前进、后退还是未知方向
beforeunload事件:用于在用户即将离开当前页面(关闭页面、刷新页面、导航到其他页面)时触发,触发该事件时,vue router会执行beforeUnloadListener函数,调用history.replaceState方法
以上两个监听的事件会在destory函数中移除
# createWebHashHistory
createWebHashHistory 会创建一个 hash 模式的路由,同createWebHistory一样,接受一个参数base,会自动给 base 加上#,再调用createWebHistory并返回
# createMemoryHistory
createMemoryHistory 会基于内存创建一个 history,主要用于处理服务端渲染 SSR,即不依赖于浏览器的实际 url 地址变化,而是在内存中维护路由历史记录。
createMemoryHistory 返回的是一个routerHistory对象,这个对象包含replace、push、listen、destroy、go方法。createMemoryHistory内部维护了两个数组listeners、quue,listeners用于记录listen方法注册的回调函数,queue用于记录路由历史记录,可以被当作一个路由队列。