2019-09-04 Vue / keep-alive

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條列表處

image

關(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)制刷新某些組件

  1. 利用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ì)被緩存

  2. 利用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ì)了解下。

  1. 官方提出的解決方案響應(yīng)路由參數(shù)的變化

  2. 利用berforeRouteEnter實(shí)現(xiàn)前進(jìn)刷新,后退緩存資料

  3. 利用第三方插件實(shí)現(xiàn)前進(jìn)刷新,后退不緩存

  4. vue中 給router-view 組件的 綁定 key 的原因

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容