vue-router 進(jìn)階

導(dǎo)航守衛(wèi)

導(dǎo)航守衛(wèi)主要用來通過跳轉(zhuǎn)或取消的方式守衛(wèi)導(dǎo)航。

參數(shù)或查詢的改變并不會(huì)觸發(fā)進(jìn)入/離開的導(dǎo)航守衛(wèi)筝闹。

1、全局守衛(wèi) router.beforeEach

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {

????// ...

})

當(dāng)一個(gè)導(dǎo)航觸發(fā)時(shí)腥光,全局前置守衛(wèi)按照創(chuàng)建順序調(diào)用关顷。守衛(wèi)是異步解析執(zhí)行,此時(shí)導(dǎo)航在所有守衛(wèi) resolve 完之前一直處于?等待中武福。

每個(gè)守衛(wèi)方法接收三個(gè)參數(shù):

to: Route: 即將要進(jìn)入的目標(biāo)?路由對(duì)象

from: Route: 當(dāng)前導(dǎo)航正要離開的路由

next: Function: 一定要調(diào)用該方法來?resolve?這個(gè)鉤子议双。執(zhí)行效果依賴?next?方法的調(diào)用參數(shù)

next(): 進(jìn)行管道中的下一個(gè)鉤子。如果全部鉤子執(zhí)行完了捉片,則導(dǎo)航的狀態(tài)就是?confirmed?(確認(rèn)的)平痰。

next(false): 中斷當(dāng)前的導(dǎo)航。如果瀏覽器的 URL 改變了(可能是用戶手動(dòng)或者瀏覽器后退按鈕)界睁,那么 URL 地址會(huì)重置到?from?路由對(duì)應(yīng)的地址觉增。

next('/')?或者?next({ path: '/' }): 跳轉(zhuǎn)到一個(gè)不同的地址。當(dāng)前的導(dǎo)航被中斷翻斟,然后進(jìn)行一個(gè)新的導(dǎo)航逾礁。你可以向?next?傳遞任意位置對(duì)象,且允許設(shè)置諸如?replace: true访惜、name: 'home'?之類的選項(xiàng)以及任何用在?router-link?的?to?prop?或?router.push?中的選項(xiàng)嘹履。

next(error): (2.4.0+) 如果傳入?next?的參數(shù)是一個(gè)?Error?實(shí)例,則導(dǎo)航會(huì)被終止且該錯(cuò)誤會(huì)被傳遞給?router.onError()?注冊(cè)過的回調(diào)债热。

確保要調(diào)用?next?方法砾嫉,否則鉤子就不會(huì)被 resolved。

2窒篱、全局后置鉤子 router.afterEach

后置鉤子和守衛(wèi)不同焕刮,這些鉤子不會(huì)接受?next?函數(shù)也不會(huì)改變導(dǎo)航本身

router.afterEach((to, from) => {

????// ...

})

3舶沿、路由獨(dú)享的守衛(wèi)

在路由配置上直接定義?beforeEnter?守衛(wèi)。

routes: [ {

????path: '/foo',

????component: Foo,????

????beforeEnter: (to, from, next) => {

????????// ...

????}

} ]?

4配并、組件內(nèi)的守衛(wèi)

可以在路由組件內(nèi)直接定義以下路由導(dǎo)航守衛(wèi):

beforeRouteEnter

beforeRouteUpdate?(2.2 新增)

beforeRouteLeave

constFoo = {

????template:`...`,

????beforeRouteEnter (to,from, next) {},

????beforeRouteUpdate (to,from, next) {},

????beforeRouteLeave (to,from, next) {}

}

beforeRouteEnter?守衛(wèi)?不能?訪問?this括荡,因?yàn)槭匦l(wèi)在導(dǎo)航確認(rèn)前被調(diào)用,因此即將登場的新組件還沒被創(chuàng)建。

不過溉旋,你可以通過傳一個(gè)回調(diào)給?next來訪問組件實(shí)例畸冲。在導(dǎo)航被確認(rèn)的時(shí)候執(zhí)行回調(diào),并且把組件實(shí)例作為回調(diào)方法的參數(shù)观腊。

beforeRouteEnter (to, from, next) {

? ? next(vm => {

? ? ????// 通過 `vm` 訪問組件實(shí)例?

????})

}

注意?beforeRouteEnter?是支持給?next?傳遞回調(diào)的唯一守衛(wèi)邑闲。對(duì)于?beforeRouteUpdate?和?beforeRouteLeave?來說,this?已經(jīng)可用了梧油,所以不支持傳遞回調(diào)苫耸,因?yàn)闆]有必要了。

beforeRouteUpdate (to, from, next) {

????// just use `this`

????this.name = to.params.name

????next()

}

這個(gè)離開守衛(wèi)通常用來禁止用戶在還未保存修改前突然離開婶溯。該導(dǎo)航可以通過?next(false)?來取消鲸阔。

beforeRouteLeave (to, from , next) {

? const answer = window.confirm('Do you really want to leave? you have unsaved changes!')

? if (answer) {

? ? next()

? } else {

? ? next(false)

? }

}


路由元信息

定義路由的時(shí)候可以配置?meta?字段

{

????path: 'bar',

????component: Bar, // a meta field

????meta: { requiresAuth: true }

}?

我們稱呼?routes?配置中的每個(gè)路由對(duì)象為?路由記錄

路由記錄可以是嵌套的迄委,因此褐筛,當(dāng)一個(gè)路由匹配成功后,他可能匹配多個(gè)路由記錄叙身。

一個(gè)路由匹配到的所有路由記錄會(huì)暴露為?$route?對(duì)象(還有在導(dǎo)航守衛(wèi)中的路由對(duì)象)的?$route.matched?數(shù)組渔扎。因此,我們需要遍歷?$route.matched?來檢查路由記錄中的?meta?字段信轿。

router.beforeEach((to, from, next) => {

? if (to.matched.some(record => record.meta.requiresAuth)) {

? ? ?// this route requires auth, check if logged in

? ? ?// if not, redirect to login page.

? ? ?if (!auth.loggedIn()) {

? ? ? next({

? ? ? ? path: '/login',

? ? ? ? query: { redirect: to.fullPath }

? ? ? })

? ? } else {

? ? ? next()

? ? }

? } else {

? ? next() // 確保一定要調(diào)用 next()? }

})


過渡效果

<router-view>是基本的動(dòng)態(tài)組件晃痴,所以我們可以用??<transition> 組件給它添加一些過渡效果

<transition name="slide">

? ? <router-view></router-view>

</transition>

動(dòng)態(tài)過度

<transition :name="transitionName">

? ? <router-view></router-view>

</transition>

// 接著在父組件內(nèi)

// watch $route 決定使用哪種過渡

watch: {

????'$route' (to, from) {

????????const toDepth = to.path.split('/').length

????????const fromDepth = from.path.split('/').length

????????this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'

????}

}


數(shù)據(jù)獲取

導(dǎo)航完成之后獲取:先完成導(dǎo)航,然后在接下來的組件生命周期鉤子中獲取數(shù)據(jù)财忽。

導(dǎo)航完成之前獲取:導(dǎo)航完成前倘核,在路由進(jìn)入的守衛(wèi)中獲取數(shù)據(jù),在數(shù)據(jù)獲取成功后執(zhí)行導(dǎo)航即彪。

1紧唱、導(dǎo)航完成之后獲取

當(dāng)使用這種方式時(shí),vue會(huì)馬上導(dǎo)航和渲染組件隶校,然后在組件的?created?鉤子中獲取數(shù)據(jù)漏益。這讓我們有機(jī)會(huì)在數(shù)據(jù)獲取期間展示一個(gè) loading 狀態(tài),還可以在不同視圖間展示不同的 loading 狀態(tài)深胳。

假設(shè)我們有一個(gè)?Post?組件绰疤,需要基于?$route.params.id?獲取文章數(shù)據(jù)

created () {

????this.fetchData()??// 組件創(chuàng)建完后獲取數(shù)據(jù),此時(shí) data 已經(jīng)被 observed 了? ?

},

watch: {

? ? '$route': 'fetchData'? ? // 如果路由有變化舞终,會(huì)再次執(zhí)行該方法? ??

},

methods: {

? ? fetchData () {

? ? ? this.error = this.post = null? ? ?

? ? ? this.loading = true? ? ? ??

? ? ? getPost(this.$route.params.id, (err, post) => {

? ? ? ? ? this.loading = false? ? ? ?

? ? ? ? ? if (err) { this.error = err.toString() } else { this.post = post }

? ? ? })

? ? }

}

2轻庆、在導(dǎo)航完成前獲取數(shù)據(jù)

通過這種方式癣猾,我們?cè)趯?dǎo)航轉(zhuǎn)入新的路由前獲取數(shù)據(jù)。

我們可以在接下來的組件的?beforeRouteEnter?守衛(wèi)中獲取數(shù)據(jù)余爆,當(dāng)數(shù)據(jù)獲取成功后只調(diào)用?next?方法煎谍。

export default {

? data () {

? ? return {

? ? ? post: null,

? ? ? error: null? ?

? ?}

?},

?beforeRouteEnter (to, from, next) {

? ? getPost(to.params.id, (err, post) => {

? ? ? next(vm => vm.setData(err, post))

? ? })

?},

?// 路由改變前,組件就已經(jīng)渲染完了? // 邏輯稍稍不同?

?beforeRouteUpdate (to, from, next) {

? ? this.post = null? ?

????getPost(to.params.id, (err, post) => {

? ? ? this.setData(err, post)

? ? ? next()

? ? })

?},

?methods: {

? ? setData (err, post) { if (err) { this.error = err.toString() } else { this.post = post }}

?}

}


在為后面的視圖獲取數(shù)據(jù)時(shí)龙屉,用戶會(huì)停留在當(dāng)前的界面,因此建議在數(shù)據(jù)獲取期間满俗,顯示一些進(jìn)度條或者別的指示转捕。如果數(shù)據(jù)獲取失敗,同樣有必要展示一些全局的錯(cuò)誤提醒唆垃。


滾動(dòng)行為?

使用前端路由五芝,當(dāng)切換到新路由時(shí),實(shí)現(xiàn)切換的頁面滾到頂部辕万,或者是保持原先的滾動(dòng)位置枢步。scrollBehavior

注意: 這個(gè)功能只在支持?history.pushState?的瀏覽器中可。

const router = new VueRouter({

? routes: [...],

? scrollBehavior (to, from, savedPosition) {

? ? // return 期望滾動(dòng)到哪個(gè)的位置?

? }

})

scrollBehavior?方法接收?to?和?from?路由對(duì)象渐尿。第三個(gè)參數(shù)?savedPosition?當(dāng)且僅當(dāng)?popstate?導(dǎo)航 (通過瀏覽器的 前進(jìn)/后退 按鈕觸發(fā)) 時(shí)才可用醉途。

{ x: number, y: number }

{ selector: string, offset? : { x: number, y: number }}?(offset 只在 2.6.0+ 支持)

如果返回一個(gè) falsy (譯者注:falsy 不是?false,參考這里)的值砖茸,或者是一個(gè)空對(duì)象隘擎,那么不會(huì)發(fā)生滾動(dòng)。

舉例:

scrollBehavior (to, from, savedPosition) {

? return { x: 0, y: 0 }

}

返回?savedPosition凉夯,在按下 后退/前進(jìn) 按鈕時(shí)货葬,就會(huì)像瀏覽器的原生表現(xiàn)那樣:

scrollBehavior (to, from, savedPosition) {

? if (savedPosition) {

? ? return savedPosition

? } else {

? ? return { x: 0, y: 0 }

? }

}

模擬『滾動(dòng)到錨點(diǎn)』的行為:

scrollBehavior (to, from, savedPosition) {

? if (to.hash) {

? ? return {

? ? ? selector: to.hash

? ? }

? }

}

異步滾動(dòng)。

返回一個(gè) Promise 來得出預(yù)期的位置描述

scrollBehavior (to, from, savedPosition) {

? return new Promise((resolve, reject) => {

? ? setTimeout(() => {

? ? ? resolve({ x: 0, y: 0 })

? ? }, 500)

? })

}



路由懶加載

當(dāng)打包構(gòu)建應(yīng)用時(shí)劲够,Javascript 包會(huì)變得非常大震桶,影響頁面加載。如果我們能把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊征绎,然后當(dāng)路由被訪問的時(shí)候才加載對(duì)應(yīng)組件蹲姐,這樣就更加高效了。

結(jié)合 Vue 的異步組件和 Webpack 的代碼分割功能炒瘸,輕松實(shí)現(xiàn)路由組件的懶加載淤堵。

首先,可以將異步組件定義為返回一個(gè) Promise 的工廠函數(shù) (該函數(shù)返回的 Promise 應(yīng)該 resolve 組件本身):

constFoo = () =>Promise.resolve({/* 組件定義對(duì)象 */})

第二顷扩,在 Webpack 2 中拐邪,我們可以使用動(dòng)態(tài) import語法來定義代碼分塊點(diǎn) (split point):

import('./Foo.vue')// 返回 Promise

注意:如果您使用的是 Babel,你將需要添加?syntax-dynamic-import?插件隘截,才能使 Babel 可以正確地解析語法扎阶。

結(jié)合這兩者汹胃,這就是如何定義一個(gè)能夠被 Webpack 自動(dòng)代碼分割的異步組件。

constFoo = () =>import('./Foo.vue')

在路由配置中什么都不需要改變东臀,只需要像往常一樣使用?Foo:

constrouter =newVueRouter({? routes: [? ? { path:'/foo', component: Foo }? ]})


把組件按組分塊

有時(shí)候我們想把某個(gè)路由下的所有組件都打包在同個(gè)異步塊 (chunk) 中着饥。只需要使用?命名 chunk,一個(gè)特殊的注釋語法來提供 chunk name (需要 Webpack > 2.4)惰赋。

constFoo = () =>import(/* webpackChunkName: "group-foo" */'./Foo.vue')

constBar = () =>import(/* webpackChunkName: "group-foo" */'./Bar.vue')

constBaz = () =>import(/* webpackChunkName: "group-foo" */'./Baz.vue')

Webpack 會(huì)將任何一個(gè)異步模塊與相同的塊名稱組合到相同的異步塊中宰掉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赁濒,隨后出現(xiàn)的幾起案子轨奄,更是在濱河造成了極大的恐慌,老刑警劉巖拒炎,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挪拟,死亡現(xiàn)場離奇詭異,居然都是意外死亡击你,警方通過查閱死者的電腦和手機(jī)玉组,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丁侄,“玉大人惯雳,你說我怎么就攤上這事∪拚希” “怎么了吨凑?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長户辱。 經(jīng)常有香客問我鸵钝,道長,這世上最難降的妖魔是什么庐镐? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任恩商,我火速辦了婚禮,結(jié)果婚禮上必逆,老公的妹妹穿的比我還像新娘怠堪。我一直安慰自己,他們只是感情好名眉,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布粟矿。 她就那樣靜靜地躺著,像睡著了一般损拢。 火紅的嫁衣襯著肌膚如雪陌粹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天福压,我揣著相機(jī)與錄音掏秩,去河邊找鬼或舞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蒙幻,可吹牛的內(nèi)容都是我干的映凳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼邮破,長吁一口氣:“原來是場噩夢啊……” “哼诈豌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起抒和,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤队询,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后构诚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铆惑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年范嘱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片员魏。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丑蛤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出撕阎,到底是詐尸還是另有隱情受裹,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布虏束,位于F島的核電站棉饶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏镇匀。R本人自食惡果不足惜照藻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汗侵。 院中可真熱鬧幸缕,春花似錦、人聲如沸晰韵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雪猪。三九已至栏尚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浪蹂,已是汗流浹背抵栈。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工告材, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人古劲。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓斥赋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親产艾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子疤剑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容