需求说明:
本文章主要是解决第三个需求。
代码如下:
(代码说明:store.state.pages是我存储标签页的列表,记录了当前打开的标签页的路由数据)
旧的方法:
//使用Vue.mixin的方法拦截了路由离开事件,并在该拦截方法中实现了销毁页面缓存的功能。
let cachePageDataList =[]
Vue.mixin({
beforeRouteLeave:function(to, from, next) {
const pages= this.$store.getters.pages.map(item =>{returnitem.name
})
const expect= ['login']if (from && expect.indexOf(from.name) < 0 && pages.indexOf(from.name) < 0) { //此处判断该路由对应的标签页是否已关闭,以此判断是否摧毁本层缓存。
const $vnode = this.$vnodeif (($vnode && $vnode.data.keepAlive) &&($vnode.parent&& $ponentInstance && $ponentInstance.cache) &&($ponentOptions)
) {var key = $vnode.key == null ? $ponentOptions.Ctor.cid + ($ponentOptions.tag ? `::${$ponentOptions.tag}` : '') : $vnode.keyvar cache =$ponentInstance.cachevar keys =$ponentInstance.keysif(cache[key]) {if (keys.length && keys.indexOf(key) > -1) {
keys.splice(keys.indexOf(key),1)
}deletecache[key]
}
}//this.$destroy()
}
next()
},
watch: {'$store.getters.pages': function(v) {
const temp=[...cachePageDataList]
const c= v.map(item =>{returnitem.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.$routeif (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.$vnodeif (($vnode && $vnode.data.keepAlive) &&($vnode.parent&& $ponentInstance && $ponentInstance.cache) &&($vnode.key||$ponentOptions)
) {var key = $vnode.key == null ? $ponentOptions.Ctor.cid + ($ponentOptions.tag ? `::${$ponentOptions.tag}` : '') : $vnode.keyvar cache =$ponentInstance.cachevar keys =$ponentInstance.keysif (!cacheList) cacheList =cacheif (!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 =>{returnitem.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)
}deletecacheList[key]
}//删除缓存的核心方法 end
}
})
}
}
}
})
新方式的思路步骤是:
1、首次任意路由时,把cacheList和keysList的指针保存起来,备用
2、每次进入路由时,将该页面的路由name和组件key保存起来,备用
3、监听到该路由页面标签关闭时,使用cacheList和keysList删除页面缓存
这里面的核心方法是如何删除页面缓存、怎么获取页面组件key?(见代码)
新方式的思路导图:
由此,可以解决卡顿的问题,提高性能。