keep-alive
keep-alive是Vue提供的一個(gè)抽象組件,用來(lái)對(duì)組件進(jìn)行緩存,從而節(jié)省性能,由于是一個(gè)抽象組件,所以在v頁(yè)面渲染完畢后不會(huì)被渲染成一個(gè)DOM元素
<keep-alive>
<loading></loading>
</keep-laive>
當(dāng)組件在keep-alive內(nèi)被切換時(shí)組件的activated、deactivated這兩個(gè)生命周期鉤子函數(shù)會(huì)被執(zhí)行
被包裹在keep-alive中的組件的狀態(tài)將會(huì)被保留,例如我們將某個(gè)列表類組件內(nèi)容滑動(dòng)到第100條位置,那么我們?cè)谇袚Q到一個(gè)組件后再次切換回到該組件,該組件的位置狀態(tài)依舊會(huì)保持在第100條列表處

關(guān)于這一點(diǎn)也是仁者見(jiàn)仁,有的產(chǎn)品可能會(huì)要求在每一次進(jìn)入一個(gè)組件時(shí)頁(yè)面的初始位置都是保持在頂部的,這里可以利用Vue中的滾動(dòng)行為,但是前提是你是HTML5 history模式
我們?cè)趧?chuàng)建一個(gè)router實(shí)例的時(shí)候,可以提供一個(gè)scrollBehavior方法,該方法會(huì)在用戶切換路由時(shí)觸發(fā)
const router=new VueRouter({
routes:[
{
path:"/",
component:Home
}
],
scrollBehavior(to,form,savedPosition){
//scrollBehavior方法接收to,form路由對(duì)象
//第三個(gè)參數(shù)savedPosition當(dāng)且僅當(dāng)在瀏覽器前進(jìn)后退按鈕觸發(fā)時(shí)才可用
//該方法會(huì)返回滾動(dòng)位置的對(duì)象信息,如果返回false,或者是一個(gè)空的對(duì)象,那么不會(huì)發(fā)生滾動(dòng)
//我們可以在該方法中設(shè)置返回值來(lái)指定頁(yè)面的滾動(dòng)位置,例如:
return {x:0,y:0}
//表示在用戶切換路由時(shí)讓是所有頁(yè)面都返回到頂部位置
//如果返回savedPosition,那么在點(diǎn)擊后退按鈕時(shí)就會(huì)表現(xiàn)的像原生瀏覽器一樣,返回的頁(yè)面會(huì)滾動(dòng)過(guò)到之前按鈕點(diǎn)擊跳轉(zhuǎn)的位置,大概寫(xiě)法如下:
if(savedPosition){
return savedPosition
}else{
return {x:0,y:0}
}
//如果想要模擬滾動(dòng)到錨點(diǎn)的行為:
if(to.hash){
return {
selector:to.hash
}
}
}
})
還有一個(gè)方法就是利用我們上面說(shuō)過(guò)的,在keep-alive激活會(huì)觸發(fā)activated鉤子函數(shù),那么在該函數(shù)內(nèi)設(shè)置scrollTop為0
被keep-alive包裹的動(dòng)態(tài)組件或router-view會(huì)緩存不活動(dòng)的實(shí)例,再次被調(diào)用這些被緩存的實(shí)例會(huì)被再次復(fù)用,對(duì)于我們的某些不是需要實(shí)時(shí)更新的頁(yè)面來(lái)說(shuō)大大減少了性能上的消耗,不需要再次發(fā)送HTTP請(qǐng)求,但是同樣也存在一個(gè)問(wèn)題就是被keep-alive包裹的組件我們請(qǐng)求獲取的數(shù)據(jù)不會(huì)再重新渲染頁(yè)面,這也就出現(xiàn)了例如我們使用動(dòng)態(tài)路由做匹配的話頁(yè)面只會(huì)保持第一次請(qǐng)求數(shù)據(jù)的渲染結(jié)果,所以需要我們?cè)谔囟ǖ那闆r下強(qiáng)制刷新某些組件
-
利用include、exclude屬性
<keep-alive include="bookLists,bookLists"> <router-view></router-view> </keep-alive> <keep-alive exclude="indexLists"> <router-view></router-view> </keep-alive>include屬性表示只有name屬性為bookLists,bookLists的組件會(huì)被緩存,(注意是組件的名字,不是路由的名字)其它組件不會(huì)被緩存exclude屬性表示除了name屬性為indexLists的組件不會(huì)被緩存,其它組件都會(huì)被緩存
-
利用meta屬性
export default[ { path:'/', name:'home', components:Home, meta:{ keepAlive:true //需要被緩存的組件 }, { path:'/book', name:'book', components:Book, meta:{ keepAlive:false //不需要被緩存的組件 } ]<keep-alive> <router-view v-if="this.$route.meat.keepAlive"></router-view> <!--這里是會(huì)被緩存的組件--> </keep-alive> <keep-alive v-if="!this.$router.meta.keepAlive"></keep-alive> <!--這里是不會(huì)被緩存的組件-->
這樣設(shè)置了之后,book頁(yè)的狀態(tài)就會(huì)保存,返回鍵返回到book時(shí)頁(yè)面不會(huì)重新渲染了。
但是有問(wèn)題?。。?!從book列表頁(yè)跳到任何頁(yè)面,再返回book列表頁(yè)都不會(huì)刷新頁(yè)面!這并不是我想要的,我只要從home主頁(yè)返回book列表頁(yè)時(shí)不刷新頁(yè)面,其他情況下是需要刷新的。
所以還需要加一些處理,思路就是從book列表頁(yè)跳轉(zhuǎn)到其他頁(yè)面時(shí)把book列表頁(yè)的keepAlive值設(shè)置為false,從home主頁(yè)返回book列表頁(yè)時(shí)把book列表頁(yè)的keepAlive值設(shè)置為true就好了,代碼如下:
book跳轉(zhuǎn)到其他頁(yè)面時(shí)把book的keepAlive值設(shè)置為false
在book列表頁(yè)加上如下代碼:
beforeRouteEnter(to, from, next) {
if(from.name=='book'){
to.meta.isBack=true;
}
next();
},
activated() {
if(this.$route.meta.isBack){
// 如果isBack是false,表明需要獲取新數(shù)據(jù),否則就不再請(qǐng)求,直接使用緩存的數(shù)據(jù)
doSomeThing...
}
// 恢復(fù)成默認(rèn)的false,避免isBack一直是true,導(dǎo)致下次無(wú)法獲取數(shù)據(jù)
this.$route.meta.isBack=false
},
鉤子函數(shù)的執(zhí)行順序
不使用keep-alive
beforeRouteEnter --> created --> mounted --> destroyed
使用keep-alive
beforeRouteEnter --> created --> mounted --> activated --> deactivated
再次進(jìn)入緩存的頁(yè)面,只會(huì)觸發(fā)beforeRouteEnter -->activated --> deactivated 。created和mounted不會(huì)再執(zhí)行。我們可以利用不同的鉤子函數(shù),做不同的事。務(wù)必理解上述鉤子函數(shù)的執(zhí)行時(shí)機(jī)和執(zhí)行順序。
activated和deactivated是使用keep-alive后,vue中比較重要的兩個(gè)鉤子函數(shù),建議詳細(xì)了解下。
官方提出的解決方案響應(yīng)路由參數(shù)的變化
利用berforeRouteEnter實(shí)現(xiàn)前進(jìn)刷新,后退緩存資料
利用第三方插件實(shí)現(xiàn)前進(jìn)刷新,后退不緩存