开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
前言
不甘于平庸又不努力
2023继续!!!
vue-router
首先下载一下源码git clone https://github.com/vuejs/vue-router.git(v3.6.5 for vue2)
项目中如何使用vue-router?
新建一个项目可以看到这样的文件
步骤就是: 安装、实例化、初始化
- import引入vue-router
- 用Vue.use() 安装 // 这个use的源码在之前已经写过了,这里简单提一下。
- 使用new Router()实例传递参数routers数组对象
- 最后使用new Vue
前端路由的具体流程:
- 访问url时,例如/login,匹配器会拿着/home去
路由映射表里面查找对应的组件,并将组件返回渲染,同时将访问记录推入历史栈中
Vue.use(Router)
Vue.use的源码中提到,接收一个plugin,这时,这个plugin就可以看做Router,是要执行这个Router里面的install方法的,这说明插件里面一定要暴露一个install方法。当在代码里运行Vue.use(Router),内部就要执行 install,并且这个方法的第一个参数我们可以拿到Vue对象,这样好处是:
作为插件的编写方不需要再额外去
import Vue
Router的install方法
vue-router的入口文件是[vue-router/src/index.js],进入后依次找到[vue-router\src\router.js],这时可以看到引入了install文件
import { install } from './install'
...
VueRouter.install = install // 当Vue.use(VueRouter)的时候 use里面就调用install方法 实际上就调用了router源码里的install方法
...
// 浏览器环境下自动安装插件
if (inBrowser && window.Vue) {
window.Vue.use(VueRouter)
}
下一步,看一下install.js的代码主要干了啥(step by step)
// 引入router-view router-link组件
import View from './components/view'
import Link from './components/link'
export let _Vue //export 一个Vue 引用
// 定义 安装install函数
export function install (Vue) {
if (install.installed && _Vue === Vue) return // 只会安装一次
install.installed = true
_Vue = Vue // 赋值给私有的Vue引用
const isDef = v => v !== undefined
const registerInstance = (vm, callVal) => {
let i = vm.$options._parentVnode
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
i(vm, callVal)
}
}
// 在beforeCreate,destroyed生命周期函数中注入路由逻辑。相当于给每个组件的beforeCreate,destroyed混入这段代码,每个组件都会运行
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) { 判断this.$options.router在不在。(因为只有我们new Vue(VueRouter)时候,router才会被保存在vue根实例的$option上)
this._routerRoot = this // this就是指的vue实例
this._router = this.$options.router
this._router.init(this) 初始化router
Vue.util.defineReactive(this, '_route', this._router.history.current) // Vue中的响应式代码,把this._route变成响应式对象,保证_route变化时,router-view会重新渲染
} else {
// 为每个组件定义_routerRoot
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
Object.defineProperty(Vue.prototype, '$router', { //在Vue原型上定义,可以直接访问:this.$router
get () { return this._routerRoot._router }
})
Object.defineProperty(Vue.prototype, '$route', { //在Vue原型上定义,可以直接访问:this.$route
get () { return this._routerRoot._route }
})
// 定义了Vue全局的组件
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
//最后设置路由组件的`beforeRouteEnter`、`beforeRouteLeave`、`beforeRouteUpdate`守卫的合并策略
const strats = Vue.config.optionMergeStrategies
// use the same hook merging strategy for route hooks
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
VueRouter 构造函数
export default class VueRouter {
...
constructor (options: RouterOptions = {}) {
....
//createMatcher通过对我们传入routes做一定的处理,将嵌套的结构处理成为一个较为容易操作的数据结构,维护成数组或是对象
this.matcher = createMatcher(options.routes || [], this)
// 图1 为这个函数的返回值 =》 this.matcher
// 图2 this.matcher.getRoutes() 可以获取当前的路由参数,就是我们项目中配置的那个数组
// 图3 this.matcher.match('/')传入一个路径可以拿到的东西,就是我饿么this.$route拿到的数据结构一样的,本质就是match方法生成的
// mode 选择路由的模式
let mode = options.mode || 'hash'
this.fallback =
mode === 'history' && !supportsPushState && options.fallback !== false
if (this.fallback) {
mode = 'hash'
}
if (!inBrowser) {
mode = 'abstract'
}
this.mode = mode
// 无论是HTML5History 和 HashHistory都会继承 ‘History’,这个History的核心方法就是`TransitionTo`
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (process.env.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${mode}`)
}
}
}
图1
图2
图3
TransitionTo主要做了两件事
- 更新当前的路由对象:updateRoute
- 触发响应式
- 执行传入的onComplete方法:confirmTransition
router-link[vue-router\src\components\link.js]
原来有这么多参数可以用,一般我们只会在项目里面用到
to
router-view[vue-router\src\components\view.js]
主要就是匹配‘name’的组件用于渲染出来,但是由于路由可以多层,所以需要深度匹配渲染
下面列举一下vue-router相关的面试题,可以一个个结合源码看一下
vue-router怎么重定向的?alias是什么
redirect表示url输入原来的地址,但是会被重定向到recirect配置的地址
alias别名
{ path: '/', component: A, alias: '/aaa' } 路由上会显示/b但是还是访问的A组件
vue-router 是什么? 它有哪些组件
这个问题可以根据上方探讨的源码进行溯源。 拥有的组件:
router-link
router-view
后记
本文仅作为自己一个阅读记录,具体还是要看大佬们的文章