vue中keepAlive的使用


在開發中經常有從列表跳到詳情頁,然后返回詳情頁的時候需要緩存列表頁的狀態(比如滾動位置信息),這個時候就需要保存狀態,要緩存狀態;vue里提供了keep-alive組件用來緩存狀態。
可以用以下幾種方案解決問題;

一、利用meta標簽

1、首先在路由中的meta標簽中記錄keepAlive的屬性為true

  path: '/classify',
    name: 'classify',
    component: () => import('@/views/classify/classify.vue'),
    meta: {
      title: '雷石淘券券',
      keepAlive: true
    }
  },

2、在創建router實例的時候加上scrollBehavior方法

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
  scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return {
        x: 0,
        y: 0
      }
    }
  }
})

3/在需要緩存的router-view組件上包裹keep-alive組件  

<keep-alive>
   <router-view v-if='$route.meta.keepAlive'></router-view>
</keep-alive>
<router-view v-if='!$route.meta.keepAlive'></router-view>

4、由於有些情況下需要緩存有些情況下不需要緩存,可以在緩存的組件里的路由鈎子函數中做判斷  

beforeRouteLeave (to, from, next) {
    this.loading = true
    if (to.path === '/goods_detail') {
      from.meta.keepAlive = true
    } else {
      from.meta.keepAlive = false
     // this.$destroy()
    }
    next()
  },

可以支持組件的緩存,但是這種方法有bug,首先第一次打開頁面的時候並不緩存,即第一次從列表頁跳到詳情頁,再回來並沒有緩存,后面在進入詳情頁才會被緩存
並且只會緩存第一次進入的狀態,不會重新請求數據,如果當頁面A選中一個分類跳到B頁面,再從B列表頁面跳往詳情頁,此時會緩存這個狀態,並且以后再從A頁面的其他分類跳到B頁面都不會重新被緩存,以至於每次從詳情頁返回B頁面都會跳第一次緩存的狀態;當你的項目只有一種狀態需要緩存,可以考慮使用這種方法

 

二 使用include、exclude屬性和beforeRouteEnter鈎子函數

首先介紹一下include和exclude vue文檔https://cn.vuejs.org/v2/api/#keep-alive
是在vue2.0以后新增的屬性
include是需要緩存的組件;
exclude是除了某些組件都緩存;
include 和 exclude 屬性允許組件有條件地緩存。二者都可以用逗號分隔字符串、正則表達式或一個數組來表示:

<keep-alive include="a,b">
  <component :is="view"></component>
</keep-alive>

<!-- 正則表達式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>

<!-- 數組 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

匹配首先檢查組件自身的 name 選項,如果 name 選項不可用,則匹配它的局部注冊名稱 (父組件 components 選項的鍵值)。匿名組件不能被匹配。

max只在2.5.0新增,最多可以緩存多少組件實例。一旦這個數字達到了,在新實例被創建之前,已緩存組件中最久沒有被訪問的實例會被銷毀掉。

<keep-alive :max="10">
  <component :is="view"></component>
</keep-alive>

 

activated 與 deactivated。

簡單介紹一下在被keep-alive包含的組件/路由中,會多出兩個生命周期的鈎子:activated 與 deactivated。
文檔:在 2.2.0 及其更高版本中,activated 和 deactivated 將會在 樹內的所有嵌套組件中觸發。
activated在組件第一次渲染時會被調用,之后在每次緩存組件被激活時調用。
activated調用時機:
第一次進入緩存路由/組件,在mounted后面,beforeRouteEnter守衛傳給 next 的回調函數之前調用:

beforeMount=> 如果你是從別的路由/組件進來(組件銷毀destroyed/或離開緩存deactivated)=>mounted=> activated 進入緩存組件 => 執行 beforeRouteEnter回調

因為組件被緩存了,再次進入緩存路由/組件時,不會觸發這些鈎子:// beforeCreate created beforeMount mounted 都不會觸發。

deactivated:組件被停用(離開路由)時調用
使用了keep-alive就不會調用beforeDestroy(組件銷毀前鈎子)和destroyed(組件銷毀),因為組件沒被銷毀,被緩存起來了。
這個鈎子可以看作beforeDestroy的替代,如果你緩存了組件,要在組件銷毀的的時候做一些事情,你可以放在這個鈎子里。
如果你離開了路由,會依次觸發:

組件內的離開當前路由鈎子beforeRouteLeave => 路由前置守衛 beforeEach =>全局后置鈎子afterEach => deactivated 離開緩存組件 => activated 進入緩存組件(如果你進入的也是緩存路由


 

項目中緩存使用方法:
1、在創建的router對象上加scrollBehavior方法,同上;
2、將需要緩存的組件加在include屬性里

<keep-alive :include="['home','classify','search']">
      <router-view></router-view>
</keep-alive>

3、在beforeRouteEnter的next回掉函數里,對返回A頁面不需要緩存的的情況初始化,即將本來需要寫在created里的東西寫在這里;注意一定要將所有的需要初始化的數據要寫一遍,不然會有bug;所以不太推薦  

beforeRouteEnter (to, from, next) {
    next(vm => {
      // 通過 `vm` 訪問組件實例
      if (from.path !== '/goods_detail') { // 一定是從A進到B頁面才刷新
        vm.titleText = vm.$route.query.name
        vm.categoryUpper = vm.$route.query.categoryUpper
        vm.goods = []
        vm.page = 1
        vm.catsIndex = 0
        vm.is_search = false
        vm.getCats2()// 是本來寫在created里面的各種
      }
    })
  }

 

三、使用include、exclude屬性和beforeRouteLeave鈎子函數和vuex (推薦使用)

第三種方法和第二種相似,不同的地方在於,將需要緩存的組件保存到全局變量,可以在路由的鈎子函數里靈活的控制哪些組件需要緩存,那些不需要緩存;跟第二種方法相比,不需要每次再重新初始化數據,但是需要在vuex中保存數據;
上代碼
1、在創建的router對象上加scrollBehavior方法,同上;
2、將需要緩存的組件加在include屬性里

<keep-alive :include="catch_components">
      <router-view></router-view>
</keep-alive>

3、在store里加入需要緩存的的組件的變量名,和相應的方法;

export default new Vuex.Store({
  state: {
    catch_components: []
  },
mutations:{
    GET_CATCHE_COMPONENTS (state, data) {
      state.catch_components = data
    }
}
})

4、在beforeRouteLeave鈎子函數里控制需要緩存的組件  

beforeRouteLeave (to, from, next) { //要在離開該組件的時候控制需要緩存的組件,否則將出現第一次不緩存的情況
    this.busy = true
    if (to.path === '/goods_detail') { // 去往詳情頁的時候需要緩存組件,其他情況下不需要緩存
      this.$store.commit('GET_CATCHE_COMPONENTS', ['home'])
    } else {
      this.$store.commit('GET_CATCHE_COMPONENTS', [])
    }
    next()
  },

另外,在我們的項目中遇到路由相同但參數不同的情況組件被復用,不更新的問題,vue官方給出了 響應路由參數變化

watch: {
    '$route' (to, from) {
      document.title = this.$route.query.name
      this.getDefault() //根據參數數據響應
    }

  },

  

  

  

  

  

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM