# vue-router
# 版本
version 3.1.5
# 作用
根据不同的路径映射到不同的视图
支持三种路由方式
- hash: 使用 URL hash 值来作路由。默认模式
- history: 依赖 HTML5 History API 和服务器配置
- abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端
提供了2种组件
- router-link
- router-view
# 路由注册
todo: 1. vue插件的注册原理 2. 组册的流程
入口文件:/src/index.js
总结:
- vue编写插件的时候通常要提供静态的install方法
- vue-router的install方法会给每一个组件注入(Vue.mixin) beforeCreated和destoryed钩子函数
- 在 beforeCreated做一些私有属性定义和路由初始化工作
# vueRouter对象
todo:1. vueRouter对象的属性和方法 2. 初始化逻辑
初始化逻辑:
- 路由初始化的时机是在组件的初始化阶段
- 执行到beforeCreated钩子函数时会执行router.init方法
- history.transitionTo方法做路由过渡
# matcher
地址: src/create-matcher.js
todo: 1. createMatcher的初始化逻辑 2. match的匹配过程
reuter配置中有通配符* 会将它移动到最后
总结:
- createMatcher的初始化就是根据路由的配置描述创建映射表,包括路径/名称到路由record的映射关系
- match会根据传入的位置和路径计算出新位置,并比配到对应的路由record,然后根据新的位置和record创建新的路径并返回
# 路径切换(导航守卫)
todo:
- 导航守卫的执行逻辑
- url的变化逻辑
- 组件渲染逻辑
transitionTo方法 跳转执行的方法
iterator 函数src/history/base.js逻辑:执行每一个导航守卫hook,并传入route,current,匿名函数,这三个参数分别对应官方文档中的to, from, next。执行匿名函数会根据一些条件执行abort或next,只有执行到next才会进到下一个导航守卫函数中
完整的导航解析流程 官方地址 (opens new window)
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
# url变化(hash模式)
源码位置:src/history/hash.js
监听路由变化 popstate / hashchange
window.addEventListener(
supportsPushState ? 'popstate' : 'hashchange',
() => {
const current = this.current
if (!ensureSlash()) {
return
}
this.transitionTo(getHash(), route => {
if (supportsScroll) {
handleScroll(this.router, route, current, true)
}
if (!supportsPushState) {
replaceHash(route.fullPath)
}
})
}
)
哈希模式下http://lcoalhost:8080变成http://lcoalhost:8080/#/
原因:实例化HashHistory时会执行ensureSlash()方法
过程:
- ensureSlash() 此时url为
http://lcoalhost:8080 - ensureSlash的path这时候为空 内部进入replaceHash('/' + path) 此时url为
http://lcoalhost:8080 - 哈希模式所以supportsPushState为false 进入getUrl() 此时url为
http://lcoalhost:8080 - window.location.replace() 这时url为
http://lcoalhost:8080/#/
# router-view组件
源码位置: src/components/view.js
todo:
- router-view如何知道渲染什么组件
在install(src/install.js)方法注册 RouterView和RouterLink组件
RouterView是一个函数式组件
this.$route 实际上是访问到 this._router.history.current
路由切换的核心 Vue.util.defineReactive(this, '_route', this._router.history.current)
this.$route是响应式的, router-view在执行render函数会访问$route,然后触发this._router的get
history.transitionTo结束后(路径发生变化), 变化后就会进行app._route的赋值(触发set 》 重新渲染)
# router-link组件
位置:src/components/link.js
todo:
- router-link如何变成标签
- 点击时如何做路径切换
通过 router.resolve计算出新路径
处理class 优先级:当前传入的class 》全局 》默认
- globalActiveClass == null ? 'router-link-active' : globalActiveClass
- globalExactActiveClass == null ? 'router-link-exact-active' : globalExactActiveClass
- this.activeClass == null ? activeClassFallback : this.activeClass
- this.exactActiveClass == null ? exactActiveClassFallback : this.exactActiveClass 处理事件,默认点击事件click 处理标签
- 如果是a标签 直接赋值href
- 如果不是就通过
findAnchor方法递归找子节点的a标签
* 找不到就不会赋值href(因为没啥意义)
- 渲染a标签
点击router-link时会执行handler方法
通过guardEvent()进行一层过滤
- 不能使用控制键重定向
- 不要在调用preventDefault时重定向
- 不要右键单击重定向
- 如果
target =“ _ blank”不要重定向 - e.preventDefault() replace参数 ? router.replace() : router.push()
# 总结
路由始终会维护当前的线路,路由切换的时候会把当前线路切换到目标线路,切换过程中会执行一系列的导航守卫钩子函数,会更改url,也会渲染对应的组件,切换完毕后会把目标线路替换当前线路,这样就会作为下一次切换路径的依据