需求說明:
本文章主要是解決第三個需求。
代碼如下:
(代碼說明:store.state.pages是我存儲標簽頁的列表,記錄了當前打開的標簽頁的路由數據)
舊的方法:
// 使用Vue.mixin的方法攔截了路由離開事件,並在該攔截方法中實現了銷毀頁面緩存的功能。 let cachePageDataList = [] Vue.mixin({ beforeRouteLeave: function (to, from, next) { const pages = this.$store.getters.pages.map(item => { return item.name }) const expect = ['login'] if (from && expect.indexOf(from.name) < 0 && pages.indexOf(from.name) < 0) { // 此處判斷該路由對應的標簽頁是否已關閉,以此判斷是否摧毀本層緩存。 const $vnode = this.$vnode if (($vnode && $vnode.data.keepAlive) && ($vnode.parent && $vnode.parent.componentInstance && $vnode.parent.componentInstance.cache) && ($vnode.componentOptions) ) { var key = $vnode.key == null ? $vnode.componentOptions.Ctor.cid + ($vnode.componentOptions.tag ? `::${$vnode.componentOptions.tag}` : '') : $vnode.key var cache = $vnode.parent.componentInstance.cache var keys = $vnode.parent.componentInstance.keys if (cache[key]) { if (keys.length && keys.indexOf(key) > -1) { keys.splice(keys.indexOf(key), 1) } delete cache[key] } } // this.$destroy() } next() }, watch: { '$store.getters.pages': function (v) { const temp = [...cachePageDataList] const c = v.map(item => { return item.name }) if (c.join(',') !== temp.join(',')) { cachePageDataList = [...c] // 判斷是否有頁面被刪除了 temp.forEach(item => { if (c.indexOf(item) < 0) { // 這個標簽頁被關閉了 console.log('%c 222222222222222222222', 'color:red;font-size:20px') console.log(item + '被關閉了,當前路由是:' + this.$route.name) const current = this.$route if (item !== current) { this.$router.push({ name: item }) // 跳轉一下這個被刪除的標簽頁,然后再調回當前頁,以此來觸發beforeLeave事件 this.$router.push(current) } } }) } } } })
舊方法的思路步驟是:
1、每次監聽到路由離開事件時,判斷是否需要清除該頁面的緩存,如果是,則清除;
2、監聽【標簽頁】的變化,如果有標簽頁被關閉了,就打開該頁面路由、再關閉,從而手動觸發路由離開事件
舊方法的核心是攔截路由離開事件,但是這種方法有缺陷是:
缺陷1、步驟2時會導致額外的路由跳轉,如果該路由下的頁面比較復雜,會導致額外的性能消耗;
缺陷2:當同時關閉多個頁面緩存時,可能導致長時間的卡頓;
由此作出一些改進。。。
------------ 分割線 -------------
新的方式:
// 使用Vue.mixin的方法存儲頁面緩存,並且當標簽頁關閉時,清除頁面緩存 let cachePageDataList = [] let cacheList, keysList const nameKeyList = {} Vue.mixin({ beforeRouteEnter (to, from, next) { next(vm => { // console.log('%c 進入頁面' + to.name, 'color:red;font-size:20px') const $vnode = vm.$vnode if (($vnode && $vnode.data.keepAlive) && ($vnode.parent && $vnode.parent.componentInstance && $vnode.parent.componentInstance.cache) && ($vnode.key || $vnode.componentOptions) ) { var key = $vnode.key == null ? $vnode.componentOptions.Ctor.cid + ($vnode.componentOptions.tag ? `::${$vnode.componentOptions.tag}` : '') : $vnode.key var cache = $vnode.parent.componentInstance.cache var keys = $vnode.parent.componentInstance.keys if (!cacheList) cacheList = cache if (!keysList) keysList = keys nameKeyList[to.name] = key // console.log(cacheList, keysList, nameKeyList) } }) }, watch: { '$store.getters.pages': function (v) { const temp = [...cachePageDataList] const newpages = v.map(item => { return item.name }) if (newpages.join(',') !== temp.join(',')) { cachePageDataList = [...newpages] // 判斷是否有頁面被刪除了 temp.forEach(item => { if (newpages.indexOf(item) < 0) { // 監聽到這個標簽頁被關閉了 // console.log('%c 這個標簽頁被關閉了:' + item, 'color:red;font-size:20px') // console.log(item + '被關閉了,當前路由是:' + this.$route.name) // 刪除緩存的核心方法 start const key = nameKeyList[item] if (key && cacheList[key]) { if (keysList.length && keysList.indexOf(key) > -1) { keysList.splice(keysList.indexOf(key), 1) } delete cacheList[key] } // 刪除緩存的核心方法 end } }) } } } })
新方式的思路步驟是:
1、首次任意路由時,把cacheList和keysList的指針保存起來,備用
2、每次進入路由時,將該頁面的路由name和組件key保存起來,備用
3、監聽到該路由頁面標簽關閉時,使用cacheList和keysList刪除頁面緩存
這里面的核心方法是如何刪除頁面緩存、怎么獲取頁面組件key?(見代碼)
新方式的思路導圖:
由此,可以解決卡頓的問題,提高性能。