vue-router源碼之history類的淺析
當(dāng)前版本: 3.0.3
類目錄: src/history/base.js
前言:
對(duì)于vue-router來說,有三種路由模式history,hash,abstract, abstract是運(yùn)行在沒有window的環(huán)境下的,這三種模式都是繼承于history類,history實(shí)現(xiàn)了一些共用的方法,對(duì)于一開始看vue-router源碼來說,可以從這里開始看起。
初始屬性
router: Router; 表示VueRouter實(shí)例。實(shí)例化History類時(shí)的第一個(gè)參數(shù) base: string; 表示基路徑。會(huì)用normalizeBase進(jìn)行規(guī)范化。實(shí)例化History類時(shí)的第二個(gè)參數(shù)。 current: Route; 表示當(dāng)前路由(route)。 pending: ?Route; 描述阻塞狀態(tài)。 cb: (r: Route) => void; 監(jiān)聽時(shí)的回調(diào)函數(shù)。 ready: boolean; 描述就緒狀態(tài)。 readyCbs: Array<Function>; 就緒狀態(tài)的回調(diào)數(shù)組。 readyErrorCbs: Array<Function>; 就緒時(shí)產(chǎn)生錯(cuò)誤的回調(diào)數(shù)組。 errorCbs: Array<Function>; 錯(cuò)誤的回調(diào)數(shù)組 // implemented by sub-classes <!-- 下面幾個(gè)是需要子類實(shí)現(xiàn)的方法,這里就先不說了,之后寫其他類實(shí)現(xiàn)的時(shí)候分析 --> +go: (n: number) => void; +push: (loc: RawLocation) => void; +replace: (loc: RawLocation) => void; +ensureURL: (push?: boolean) => void; +getCurrentLocation: () => string;
對(duì)于history類來說,主要是下下面兩個(gè)函數(shù)的邏輯
transitionTo
這個(gè)方法主要是對(duì)路由跳轉(zhuǎn)的封裝, location接收的是HTML5History,HashHistory,AbstractHistory, onComplete是成功的回調(diào),onAbort是失敗的回調(diào)
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const route = this.router.match(location, this.current) // 解析成每一個(gè)location需要的route
this.confirmTransition(route, () => {
this.updateRoute(route)
onComplete && onComplete(route)
this.ensureURL()
// fire ready cbs once
if (!this.ready) {
this.ready = true
this.readyCbs.forEach(cb => { cb(route) })
}
}, err => {
if (onAbort) {
onAbort(err)
}
if (err && !this.ready) {
this.ready = true
this.readyErrorCbs.forEach(cb => { cb(err) })
}
})
}
confirmTransition
這是方法是確認(rèn)跳轉(zhuǎn),route是匹配的路由對(duì)象, onComplete是匹配成功的回調(diào), 是匹配失敗的回調(diào)
confirmTransition(route: Route, onComplete: Function, onAbort?: Function) {
const current = this.current
const abort = err => { // 異常處理函數(shù)
if (isError(err)) {
if (this.errorCbs.length) {
this.errorCbs.forEach(cb => { cb(err) })
} else {
warn(false, 'uncaught error during route navigation:')
console.error(err)
}
}
onAbort && onAbort(err)
}
if (
isSameRoute(route, current) &&
// in the case the route map has been dynamically appended to
route.matched.length === current.matched.length
) {
this.ensureURL()
return abort()
}
<!-- 根據(jù)當(dāng)前路由對(duì)象和匹配的路由:返回更新的路由、激活的路由、停用的路由 -->
const {
updated,
deactivated,
activated
} = resolveQueue(this.current.matched, route.matched)
<!-- 需要執(zhí)行的任務(wù)隊(duì)列 -->
const queue: Array<?NavigationGuard> = [].concat(
// beforeRouteLeave 鉤子函數(shù)
extractLeaveGuards(deactivated),
// 全局的beforeHooks勾子
this.router.beforeHooks,
// beforeRouteUpdate 鉤子函數(shù)調(diào)用
extractUpdateHooks(updated),
// config里的勾子
activated.map(m => m.beforeEnter),
// async components
resolveAsyncComponents(activated)
)
this.pending = route
<!-- 對(duì)于queue數(shù)組所執(zhí)行的迭代器方法 -->
const iterator = (hook: NavigationGuard, next) => {
if (this.pending !== route) {
return abort()
}
try {
hook(route, current, (to: any) => {
if (to === false || isError(to)) {
// next(false) -> abort navigation, ensure current URL
this.ensureURL(true)
abort(to)
} else if (
typeof to === 'string' ||
(typeof to === 'object' && (
typeof to.path === 'string' ||
typeof to.name === 'string'
))
) {
// next('/') or next({ path: '/' }) -> redirect
abort()
if (typeof to === 'object' && to.replace) {
this.replace(to)
} else {
this.push(to)
}
} else {
// confirm transition and pass on the value
next(to)
}
})
} catch (e) {
abort(e)
}
}
runQueue(queue, iterator, () => {
const postEnterCbs = []
const isValid = () => this.current === route
<!-- beforeRouteEnter 鉤子函數(shù)調(diào)用 -->
const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)
const queue = enterGuards.concat(this.router.resolveHooks)
<!-- 迭代運(yùn)行queue -->
runQueue(queue, iterator, () => {
if (this.pending !== route) {
return abort()
}
this.pending = null
onComplete(route)
if (this.router.app) {
this.router.app.$nextTick(() => {
postEnterCbs.forEach(cb => { cb() })
})
}
})
})
}
結(jié)語:
每一次總結(jié),都是對(duì)之前讀源碼的再一次深入的了解
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
nginx部署多個(gè)vue項(xiàng)目的方法示例
這篇文章主要介紹了nginx部署多個(gè)vue項(xiàng)目的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
vue從零實(shí)現(xiàn)一個(gè)消息通知組件的方法詳解
這篇文章主要介紹了vue從零實(shí)現(xiàn)一個(gè)消息通知組件的方法,結(jié)合實(shí)例形式分析了vue實(shí)現(xiàn)消息通知組件的具體原理、實(shí)現(xiàn)步驟、與相關(guān)操作技巧,需要的朋友可以參考下2020-03-03
使用vue項(xiàng)目配置多個(gè)代理的注意點(diǎn)
這篇文章主要介紹了使用vue項(xiàng)目配置多個(gè)代理的注意點(diǎn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
vue跳轉(zhuǎn)外部鏈接始終有l(wèi)ocalhost的問題
這篇文章主要介紹了vue跳轉(zhuǎn)外部鏈接始終有l(wèi)ocalhost的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
vue實(shí)現(xiàn)移動(dòng)端輕量日期組件不依賴第三方庫的方法
這篇文章主要介紹了vue 移動(dòng)端輕量日期組件不依賴第三方庫,需要的朋友可以參考下2019-04-04

