由於本人開發中使用的是VUE技術棧,最近也是開始源碼的學習,以此記錄我的理解,若行文有誤,請多多指教。vue
在vue中咱們使用vue-router時須要先進行new Router()
,執行new Router()
後主要執行代碼看看VueRouter class定義的constructor
方法。node
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}`)
}
}
}
複製代碼
從代碼裏面咱們能夠看到在new
的時候肯定了使用何種路由模式,而且根據傳入options建立matcher
。vue-router
接下來看看當使用vue.use()
執行install方法作了什麼:bash
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
}
複製代碼
install
方法裏主要是Vue.mixin
給每一個組件混入了beforeCreate
和 destroyed
方法,在Vue的原型鏈上增長了$router
和$route
對象,這就是爲何咱們使用Vue的時候在this上能夠拿到這兩個對象,註冊了router-view
和router-link
兩個組件。app
接下來看看matcher
的定義:學習
export type Matcher = {
match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;
addRoutes: (routes: Array<RouteConfig>) => void;
};
複製代碼
matcher
暴露了match
方法addRoutes
方法,從方法的名字上看,match方法是用於路由匹配,addRoutes則是用來添加路由配置。ui
在執行creatMatcher()
裏第一代段代碼生成了pathList
、pathMap
、nameMap
這三個對象,這是後面路由執行匹配很是重要的配置。this
const { pathList, pathMap, nameMap } = createRouteMap(routes)
複製代碼
pathMap
和nameMap
分別是以route配置的path和name爲key生成的一個映射表,對應value爲RouteRecord
實例。spa
下面看看RouteRecord
的定義:prototype
declare type RouteRecord = {
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>;
}
複製代碼
結合代碼裏的實際數據對照理解各個屬性的含義:
key | value |
---|---|
path | 傳入的路徑值 |
regex | 根據path生成的正則匹配規則 |
components | path對應的組件 |
instances | 執行路由守衛方法時傳入的route實例 |
name | route的name |
parent | route的父級,是一個遞歸的對象,從最底層一直到最頂層,無則爲undefined |
redirect | 重定向的路徑 |
matchAs | 用於匹配alias |
props | 傳入路由的參數 |
結合以上解釋,咱們能夠得出vue-router
一個大概的運行概念。
執行new Router()
生成路由配置對象routedRecord
路由匹配根據route
對象的regex
進行匹配
根據route
的parent
對象遞歸獲取component
組件生成render Tree
執行各組件對應的導航守衛方法
此文大概簡述了vue-router是如何執行的,可是對於router跳轉的具體執行並無進行深刻解釋,下一篇文章將會詳細說明router跳轉以後是如何執行。