在開發中常常有從列表跳到詳情頁,而後返回詳情頁的時候須要緩存列表頁的狀態(好比滾動位置信息),這個時候就須要保存狀態,要緩存狀態;vue裏提供了keep-alive組件用來緩存狀態。
能夠用如下幾種方案解決問題;html
直接上代碼,
一、首先在路由中的meta標籤中記錄keepAlive的屬性爲truevue
path: '/classify', name: 'classify', component: () => import('@/views/classify/classify.vue'), meta: { title: '雷石淘券券', keepAlive: true } },
二、在建立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組件vuex
<keep-alive> <router-view v-if='$route.meta.keepAlive'></router-view> </keep-alive><router-view v-if='!$route.meta.keepAlive'></router-view>
四、因爲有些狀況下須要緩存有些狀況下不須要緩存,能夠在緩存的組件裏的路由鉤子函數中作判斷api
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 vue文檔(https://cn.vuejs.org/v2/api/#...
是在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 選項的鍵值)。匿名組件不能被匹配。ide
max只在2.5.0新增,最多能夠緩存多少組件實例。一旦這個數字達到了,在新實例被建立以前,已緩存組件中最久沒有被訪問的實例會被銷燬掉。函數
<keep-alive :max="10"> <component :is="view"></component> </keep-alive>
簡單介紹一下在被keep-alive包含的組件/路由中,會多出兩個生命週期的鉤子:activated 與 deactivated。
文檔:在 2.2.0 及其更高版本中,activated 和 deactivated 將會在 樹內的全部嵌套組件中觸發。
activated在組件第一次渲染時會被調用,以後在每次緩存組件被激活時調用。
activated調用時機:
第一次進入緩存路由/組件,在mounted後面,beforeRouteEnter守衛傳給 next 的回調函數以前調用:ui
beforeMount=> 若是你是從別的路由/組件進來(組件銷燬destroyed/或離開緩存deactivated)=>mounted=> activated 進入緩存組件 => 執行 beforeRouteEnter回調
由於組件被緩存了,再次進入緩存路由/組件時,不會觸發這些鉤子:// beforeCreate created beforeMount mounted 都不會觸發。
deactivated:組件被停用(離開路由)時調用
使用了keep-alive就不會調用beforeDestroy(組件銷燬前鉤子)和destroyed(組件銷燬),由於組件沒被銷燬,被緩存起來了。
這個鉤子能夠看做beforeDestroy的替代,若是你緩存了組件,要在組件銷燬的的時候作一些事情,你能夠放在這個鉤子裏。
若是你離開了路由,會依次觸發:
組件內的離開當前路由鉤子beforeRouteLeave => 路由前置守衛 beforeEach =>全局後置鉤子afterEach => deactivated 離開緩存組件 => activated 進入緩存組件(若是你進入的也是緩存路由
項目中緩存使用方法:
一、在建立的router對象上加scrollBehavior方法,同上;
二、將須要緩存的組件加在include屬性裏
<keep-alive :include="['home','classify','search']"> <router-view></router-view> </keep-alive>
三、在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裏面的各類 } }) }
第三種方法和第二種類似,不一樣的地方在於,將須要緩存的組件保存到全局變量,能夠在路由的鉤子函數裏靈活的控制哪些組件須要緩存,那些不須要緩存;跟第二種方法相比,不須要每次再從新初始化數據,可是須要在vuex中保存數據;
上代碼
一、在建立的router對象上加scrollBehavior方法,同上;
二、將須要緩存的組件加在include屬性裏
<keep-alive :include="catch_components"> <router-view></router-view> </keep-alive>
三、在store里加入須要緩存的的組件的變量名,和相應的方法;
export default new Vuex.Store({ state: { catch_components: [] }, mutations:{ GET_CATCHE_COMPONENTS (state, data) { state.catch_components = data } } })
三、在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項目裏使用keep-alive的狀況,網上有一些配合this.$destroy()方法使用的,但我在使用過程當中驗證了,並很差用;若是有多個狀態,而且有選擇的緩存,那麼第三個方法是最好的選擇;若是你不想用vuex使用第二種方法也能夠,但須要注意初始化數據。
另外,在咱們的項目中遇到路由相同但參數不一樣的狀況組件被複用,不更新的問題,vue官方給出了 響應路由參數變化
watch: { '$route' (to, from) { document.title = this.$route.query.name this.getDefault() //根據參數數據響應 } },