Because I use VUE technology stack, recently also began to learn source code, in order to record personal understanding, if the text is wrong, please give advice.
1. The new Router and install
In vUE, we need to perform new router () first. After executing new router (), we should look at the constructor method defined by the VueRouter class.
constructor (options: RouterOptions = {}) { this.app = null this.apps = [] this.options = options this.beforeHooks = [] this.resolveHooks = [] this.afterHooks = [] this.matcher = createMatcher(options.routes || [], this)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
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}`)}}}Copy the code
From the code we can see that the new mode determines which route to use and creates the matcher based on the options passed in.
Let’s see what happens when you execute the install method with vue.use() :
export function install (Vue) {
if (install.installed && _Vue === Vue) return
install.installed = true_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)
}
}
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this, '_route', this._router.history.current)
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
Object.defineProperty(Vue.prototype, '$router', {
get () { return this._routerRoot._router }
})
Object.defineProperty(Vue.prototype, '$route', {
get () { return this._routerRoot._route }
})
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
const strats = Vue.config.optionMergeStrategies
// use the same hook merging strategy for route hooks
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
Copy the code
We added the $router and $route objects to the prototype link of Vue. This is why we can get these two objects from Vue when we use Vue. We also added the “beforeCreate” and “Destroyed” methods to each component. The router-view and router-link components are registered. Procedure
2. The matcher and the route
Let’s look at Matcher’s definition:
export typeMatcher = { match: (raw: RawLocation, current? : Route, redirectedFrom? : Location) => Route; addRoutes: (routes: Array<RouteConfig>) => void; };Copy the code
Matcher exposes the match method addRoutes, which is used to match routes and addRoutes to add route configurations.
The first generation of code in the creatMatcher() execution generates the pathList, pathMap, and nameMap objects, which are very important configurations for subsequent route matching.
const { pathList, pathMap, nameMap } = createRouteMap(routes)
Copy the code
PathMap and nameMap respectively generate a mapping table with the path and name configured with route as the keys. The corresponding value is the RouteRecord instance.
Let’s look at the definition of RouteRecord:
declare typeRouteRecord = { path: string; regex: RouteRegExp; components: Dictionary<any>; instances: Dictionary<any>; name: ? string; parent: ? RouteRecord; redirect: ? RedirectOption; matchAs: ? string; beforeEnter: ? NavigationGuard; meta: any; props: boolean | Object | Function | Dictionary<boolean | Object | Function>; }Copy the code
Understand the meaning of each attribute against the actual data in the code:
key | value |
---|---|
path | The value of the path passed in |
regex | The regular match rules generated by path |
components | Path component |
instances | The route instance passed in when the route guard method is executed |
name | The name of the route |
parent | The parent of route is a recursive object that runs from the lowest level to the highest level |
redirect | Redirected path |
matchAs | Used to match aliases |
props | The parameters of the incoming route |
Combined with the above explanation, we can get a general concept of how vue-Router works.
-
Run new Router() to generate the routedRecord route configuration object
-
Route matching Matches based on the regex of the route object
-
Generate a Render Tree by recursively fetching the Component from the route parent object
-
Execute the navigation guard method for each component
This article gives an overview of how vue-Router is executed, but there is no in-depth explanation of how router hops are executed. The next article will explain in detail how router hops are executed.