需求说明:
本文章主要是解决第三个需求。
代码如下:
(代码说明: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?(见代码)
新方式的思路导图:
由此,可以解决卡顿的问题,提高性能。