在使用Vue開發管理系統項目的時候,爲了保存頁面的瀏覽狀態,咱們可使用內置組件keep-alive
來緩存組件內部狀態,避免從新渲染。vue
<keep-alive> <router-view></router-view> </keep-alive>
被keep-alive包裹的動態組件或router-view會緩存不活動的實例,再次被調用這些被緩存的實例會被再次複用,而不須要再次發送HTTP請求。對於使用tabs標籤頁打開頁面時,這正是咱們想要的效果。可是這樣作同時也存在一個問題,就是被keep-alive包裹的組件會保持最後一次請求數據的渲染結果,即便咱們關閉了tabs頁,再次打開時依舊是上一次的狀態。這時,咱們就得用上include、exclude屬性來對緩存的組件進行篩選。node
Props:正則表達式
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>
有了include和exclude對組件進行篩選,而後動態的記錄tabs中打開的組件名,這就完美的解決了動態緩存的問題。因此在配置路由文件時,咱們必須得先import組件,而後以組件名調用。數組
import HelloWorld from '@/components/HelloWorld'
routes: [ { path: '/', name: 'HelloWorld', component: HelloWorld }
可是,在項目開發中,爲了提高頁面加載的速度,通常會採用路由懶加載的方式加載路由組件,這時調用的組件再也不是經過組件名,而是匿名組件。緩存
{ path: '/home', name: 'home', component: resolve => require(['@/components/learn/home'], resolve) }
但是,官方文檔指出:post
匹配首先檢查組件自身的 name 選項,若是 name 選項不可用,則匹配它的局部註冊名稱 (父組件 components 選項的鍵值)。匿名組件不能被匹配。
這樣一來include和exclude就無效了。。。ui
額(⊙o⊙)…目前咱們項目就是這樣經過匿名組件調用的,因此就沒有使用keep-alive組件。這時領導試用系統,咦...我這打開的頁面怎麼每次點進去都重置了頁面內容,怎麼不能像打開網頁那樣,我看到哪就給保存那時的狀態呢,不過因爲你們說弄不了,就把這個功能推掉了。this
可是這段時間正好手中的事告一段落了,有空餘時間,並本着有問題就得解決的原則,就本身琢磨起來。首先使用keep-alive進行全站緩存這個是確定不行的,使用者確定得說:怎麼我把頁面關了打開後仍是以前的呢。。。因此,感受這是一個很複雜的問題,要否則早就加上了。spa
因而乎,打開度娘尋找心靈安慰。找吖找吖找,也不知在清一色的複製粘帖中摸索了多久,除了使用include來解決動態緩存問題,徹底沒有對匿名組件的解決方案。就在快要放棄和度娘交流時,忽然眼前閃過一絲但願的光芒!code
在茫茫代碼中,他一眼就看到了隱藏在角落裏的vue-component-12-keep-alive,而後纔有了完美的解決方案。那就是使用Vue.mixin的方法攔截了路由離開事件,並在該攔截方法中實現了銷燬頁面緩存的功能。
// 全局混入,關閉tab時清除組件緩存 Vue.mixin({ beforeRouteLeave(to, from, next) { let flag = true this.$store.state.options.forEach(e => { // options存儲打開的tabs的組件路由 if(from.path == e.route) { flag = false } }) if(flag && this.$vnode.parent && this.$vnode.parent.componentInstance.cache) { let key = this.$vnode.key // 當前關閉的組件名 let cache = this.$vnode.parent.componentInstance.cache // 緩存的組件 let keys = this.$vnode.parent.componentInstance.keys // 緩存的組件名 if(cache[key] != null) { delete cache[key] let index = keys.indexOf(key) if(index > -1) { keys.splice(index, 1) } } } next() } })
不過在這以前咱們還得解決一個問題,因爲此方法是攔截了路由離開事件,而當咱們關閉不是當前激活的標籤頁時是不會觸發路由離開事件的,這就會致使清除該緩存失效,因此咱們得在關閉不激活的標籤頁時先模擬一次點擊事件才能達到預期的效果。
// 移除tab標籤 tabRemove (targetName) { let event = new Event('click') document.getElementById("tab-" + targetName).dispatchEvent(event) // 觸發點擊事件 this.$store.commit('delete_tabs', targetName); if (this.activeIndex === targetName) { // 設置當前激活的路由 if (this.openTab && this.openTab.length >= 1) { this.$store.commit('set_active_index', this.openTab[this.openTab.length - 1].route); this.$router.push({ path: this.activeIndex }); } else { this.$router.push({ path: '/' }); } } }
OK,這樣就完美瞭解決了匿名組件動態清除緩存的問題了。