前言
說到Vue的鉤子函數(shù)费封,可能很多人只停留在一些很簡單常用的鉤子(created,mounted)焕妙,而且對于里面的區(qū)別,什么時候該用什么鉤子弓摘,并沒有仔細的去研究過焚鹊,且Vue的生命周期在面試中也算是比較高頻的考點,那么該如何回答這類問題韧献,讓人有眼前一亮的感覺呢...
Vue-Router導航守衛(wèi):
有的時候末患,我們需要通過路由來進行一些操作,比如最常見的登錄權限驗證锤窑,當用戶滿足條件時璧针,才讓其進入導航,否則就取消跳轉(zhuǎn)渊啰,并跳到登錄頁面讓其登錄探橱。
為此我們有很多種方法可以植入路由的導航過程:全局的, 單個路由獨享的, 或者組件級的,推薦優(yōu)先閱讀路由文檔
全局守衛(wèi)
vue-router全局有三個守衛(wèi):
router.beforeEach 全局前置守衛(wèi) 進入路由之前
router.beforeResolve 全局解析守衛(wèi)(2.5.0+) 在beforeRouteEnter調(diào)用之后調(diào)用
router.afterEach 全局后置鉤子 進入路由之后
使用方法:
to,from,next 這三個參數(shù):
to和from是將要進入和將要離開的路由對象,路由對象指的是平時通過this.$route獲取到的路由對象。
next:Function 這個參數(shù)是個函數(shù)绘证,且必須調(diào)用走搁,否則不能進入路由(頁面空白)。
next() 進入該路由迈窟。
next(false): 取消進入路由私植,url地址重置為from路由地址(也就是將要離開的路由地址)。
next 跳轉(zhuǎn)新路由车酣,當前的導航被中斷曲稼,重新開始一個新的導航索绪。
我們可以這樣跳轉(zhuǎn):next('path地址')或者next({path:''})或者next({name:''})
且允許設置諸如 replace: true、name: 'home' 之類的選項
以及你用在router-link或router.push的對象選項贫悄。
路由獨享守衛(wèi)
如果你不想全局配置守衛(wèi)的話瑞驱,你可以為某些路由單獨配置守衛(wèi):
路由組件內(nèi)的守衛(wèi):
beforeRouteEnter 進入路由前
beforeRouteUpdate (2.2) 路由復用同一個組件時
beforeRouteLeave 離開當前路由時
文檔中的介紹:
beforeRouteEnter訪問this
因為鉤子在組件實例還沒被創(chuàng)建的時候調(diào)用,所以不能獲取組件實例 this窄坦,可以通過傳一個回調(diào)給next來訪問組件實例唤反。
但是回調(diào)的執(zhí)行時機在mounted后面,所以在我看來這里對this的訪問意義不太大,可以放在created或者mounted里面鸭津。
beforeRouteLeave:
導航離開該組件的對應路由時調(diào)用彤侍,我們用它來禁止用戶離開,比如還未保存草稿逆趋,或者在用戶離開前盏阶,將setInterval銷毀,防止離開之后闻书,定時器還在調(diào)用名斟。
關于鉤子的一些知識:
路由鉤子函數(shù)的錯誤捕獲
如果我們在全局守衛(wèi)/路由獨享守衛(wèi)/組件路由守衛(wèi)的鉤子函數(shù)中有錯誤,可以這樣捕獲:
在路由文檔中還有更多的實例方法:動態(tài)添加路由等魄眉,有興趣可以了解一下砰盐。
跳轉(zhuǎn)死循環(huán),頁面永遠空白
我了解到的坑律,很多人會碰到這個問題楞卡,來看一下這段偽代碼:
看邏輯貌似是對的,但是當我們跳轉(zhuǎn)到login之后脾歇,因為此時還是未登錄狀態(tài)蒋腮,所以會一直跳轉(zhuǎn)到login然后死循環(huán),頁面一直是空白的藕各,所以:我們需要把判斷條件稍微改一下池摧。
全局后置鉤子的跳轉(zhuǎn):
文檔中提到因為router.afterEach不接受next函數(shù)所以也不會改變導航本身,意思就是只能當成一個鉤子來使用激况,但是我自己在試的時候發(fā)現(xiàn)作彤,我們可以通過這種形式來實現(xiàn)跳轉(zhuǎn):
額,通過router.beforeEach 也完全可以實現(xiàn)且更好乌逐,我就騷一下竭讳。
完整的路由導航解析流程(不包括其他生命周期):
觸發(fā)進入其他路由。
調(diào)用要離開路由的組件守衛(wèi)beforeRouteLeave
調(diào)用局前置守衛(wèi):beforeEach
在重用的組件里調(diào)用beforeRouteUpdate
調(diào)用路由獨享守衛(wèi)beforeEnter浙踢。
解析異步路由組件绢慢。
在將要進入的路由組件中調(diào)用beforeRouteEnter
調(diào)用全局解析守衛(wèi)beforeResolve
導航被確認。
調(diào)用全局后置鉤子的afterEach 鉤子洛波。
觸發(fā)DOM更新(mounted)胰舆。
執(zhí)行beforeRouteEnter 守衛(wèi)中傳給 next 的回調(diào)函數(shù)
你不知道的keep-alive[我猜你不知道]
在開發(fā)Vue項目的時候骚露,大部分組件是沒必要多次渲染的,所以Vue提供了一個內(nèi)置組件keep-alive來緩存組件內(nèi)部狀態(tài)缚窿,避免重新渲染棘幸,keep-alive
文檔:和 <transition>相似,<keep-alive> 是一個抽象組件:它自身不會渲染一個 DOM 元素倦零,也不會出現(xiàn)在父組件鏈中误续。
用法:
緩存動態(tài)組件:
緩存路由組件:
使用keep-alive可以將所有路徑匹配到的路由組件都緩存起來,包括路由組件里面的組件扫茅,keep-alive大多數(shù)使用場景就是這種蹋嵌。
生命周期鉤子:
這篇既然是Vue鉤子函數(shù)的專場,那肯定要扣題呀~
在被keep-alive包含的組件/路由中诞帐,會多出兩個生命周期的鉤子:activated與 deactivated欣尼。
文檔:在 2.2.0 及其更高版本中爆雹,activated 和 deactivated 將會在? 樹內(nèi)的所有嵌套組件中觸發(fā)停蕉。
activated在組件第一次渲染時會被調(diào)用,之后在每次緩存組件被激活時調(diào)用钙态。
activated調(diào)用時機:
第一次進入緩存路由/組件慧起,在mounted后面,beforeRouteEnter守衛(wèi)傳給 next 的回調(diào)函數(shù)之前調(diào)用:
beforeMount=> 如果你是從別的路由/組件進來(組件銷毀destroyed/或離開緩存deactivated)=>mounted=> activated 進入緩存組件 => 執(zhí)行 beforeRouteEnter回調(diào)
因為組件被緩存了册倒,再次進入緩存路由/組件時蚓挤,不會觸發(fā)這些鉤子:
// beforeCreate created beforeMount mounted 都不會觸發(fā)。
所以之后的調(diào)用時機是:
組件銷毀destroyed/或離開緩存deactivated => activated 進入當前緩存組件?=> 執(zhí)行 beforeRouteEnter回調(diào)
? // 組件緩存或銷毀驻子,嵌套組件的銷毀和緩存也在這里觸發(fā)
deactivated:組件被停用(離開路由)時調(diào)用
使用了keep-alive就不會調(diào)用beforeDestroy(組件銷毀前鉤子)和destroyed(組件銷毀)灿意,因為組件沒被銷毀,被緩存起來了崇呵。
這個鉤子可以看作beforeDestroy的替代缤剧,如果你緩存了組件,要在組件銷毀的的時候做一些事情域慷,你可以放在這個鉤子里荒辕。
如果你離開了路由,會依次觸發(fā):
組件內(nèi)的離開當前路由鉤子beforeRouteLeave =>? 路由前置守衛(wèi) beforeEach =>全局后置鉤子afterEach => deactivated 離開緩存組件 => activated 進入緩存組件(如果你進入的也是緩存路由)
如果離開的組件沒有緩存的話 beforeDestroy會替換deactivated
如果進入的路由也沒有緩存的話? 全局后置鉤子afterEach=>銷毀 destroyed=> beforeCreate等
那么犹褒,如果我只是想緩存其中幾個路由/組件抵窒,那該怎么做?
緩存你想緩存的路由:
Vue2.1.0之前:
想實現(xiàn)類似的操作叠骑,你可以:
配置一下路由元信息
創(chuàng)建兩個keep-alive標簽
使用v-if通過路由元信息判斷緩存哪些路由李皇。
Vue2.1.0版本之后:
使用路由元信息的方式,要多創(chuàng)建一個router-view標簽宙枷,并且每個路由都要配置一個元信息疙赠,是可以實現(xiàn)我們想要的效果付材,但是過于繁瑣了點。
幸運的是在Vue2.1.0之后圃阳,Vue新增了兩個屬性配合keep-alive來有條件地緩存 路由/組件厌衔。
新增屬性:
include:匹配的 路由/組件 會被緩存
exclude:匹配的 路由/組件 不會被緩存
include和exclude支持三種方式來有條件的緩存路由:采用逗號分隔的字符串形式,正則形式捍岳,數(shù)組形式富寿。
正則和數(shù)組形式,必須采用v-bind形式來使用锣夹。
緩存組件的使用方式:
但更多場景中页徐,我們會使用keep-alive來緩存路由:
匹配規(guī)則:
1、首先匹配組件的name選項银萍,如果name選項不可用变勇。
2、則匹配它的局部注冊名稱贴唇。 (父組件 components 選項的鍵值)
3搀绣、匿名組件,不可匹配戳气。
比如路由組件沒有name選項链患,并且沒有注冊的組件名。
4瓶您、只能匹配當前被包裹的組件麻捻,不能匹配更下面嵌套的子組件。
比如用在路由上呀袱,只能匹配路由組件的name選項贸毕,不能匹配路由組件里面的嵌套組件的name選項。
5夜赵、文檔:不會在函數(shù)式組件中正常工作明棍,因為它們沒有緩存實例。
6油吭、exclude的優(yōu)先級大于include
也就是說:當include和exclude同時存在時击蹲,exclude生效,include不生效婉宰。
當組件被exclude匹配歌豺,該組件將不會被緩存,不會調(diào)用activated 和 deactivated心包。
組件生命周期鉤子:
關于組件的生命周期类咧,是時候放出這張圖片了:
這張圖片已經(jīng)講得很清楚了,很多人這部分也很清楚了,大部分生命周期并不會用到痕惋,這里提一下幾點:
ajax請求最好放在created里面区宇,因為此時已經(jīng)可以訪問this了,請求到數(shù)據(jù)就可以直接放在data里面值戳。這里也碰到過幾次议谷,面試官問:ajax請求應該放在哪個生命周期。
關于dom的操作要放在mounted里面堕虹,在mounted前面訪問dom會是undefined卧晓。
每次進入/離開組件都要做一些事情,用什么鉤子:
不緩存:
進入的時候可以用created和mounted鉤子赴捞,離開的時候用beforeDestory和destroyed鉤子,beforeDestory可以訪問this逼裆,destroyed不可以訪問this。
緩存了組件:
緩存了組件之后赦政,再次進入組件不會觸發(fā)beforeCreate胜宇、created 、beforeMount恢着、 mounted桐愉,如果你想每次進入組件都做一些事情的話,你可以放在activated進入緩存組件的鉤子中然评。
同理:離開緩存組件的時候仅财,beforeDestroy和destroyed并不會觸發(fā)狈究,可以使用deactivated離開緩存組件的鉤子來代替碗淌。
觸發(fā)鉤子的完整順序:
將路由導航、keep-alive抖锥、和組件生命周期鉤子結(jié)合起來的亿眠,觸發(fā)順序,假設是從a組件離開磅废,第一次進入b組件:
beforeRouteLeave:路由組件的組件離開路由前鉤子纳像,可取消路由離開。
beforeEach: 路由全局前置守衛(wèi)拯勉,可用于登錄驗證竟趾、全局路由loading等。
beforeEnter: 路由獨享守衛(wèi)
beforeRouteEnter: 路由組件的組件進入路由前鉤子宫峦。
beforeResolve:路由全局解析守衛(wèi)
afterEach:路由全局后置鉤子
beforeCreate:組件生命周期岔帽,不能訪問this。
created:組件生命周期导绷,可以訪問this,不能訪問dom。
beforeMount:組件生命周期
deactivated: 離開緩存組件a蛤高,或者觸發(fā)a的beforeDestroy和destroyed組件銷毀鉤子。
mounted:訪問/操作dom钦购。
activated:進入緩存組件,進入a的嵌套子組件(如果有的話)褂萧。
執(zhí)行beforeRouteEnter回調(diào)函數(shù)next押桃。
結(jié)語
Vue提供了很多鉤子,但很多鉤子我們幾乎不會用到导犹,只有清楚這些鉤子函數(shù)的觸發(fā)順序以及背后的一些限制等怨规,這樣我們才能夠正確的使用這些鉤子,希望看了本文的同學锡足,能對這些鉤子有更加清晰的認識波丰,使用起來更加得心應手。