在使用vue-element-admin
4.2.1 作为模板进行开发的时候, 发现该模板的缓存存在一些问题(未在官方示例下调试), 比如切换路由时不被释放的问题, 不知道最新版本是否存在, 这里记录一下影响最小的改动方法和思路.
Demo情况
路由组件:
ChartIndexView
路由组件 - 列表页面ChartEditView
路由组件 - 编辑页面
模板:
keep-alive
缓存组件 (include
内组件名称符合配置要求)router-view
路由渲染组件
Vuex:
visitedViews
已打开标签页
所有路由组件
的路由信息
(每次新增或关闭都会维护该对象)cachedViews
当前的路由组件的名称name
AppMain.vue 如下
1
2
3
4
5
6
7
8
9
10
<template>
<section class="app-main">
<!-- 常规页面 -->
<transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews">
<router-view :key="key" />
</keep-alive>
</transition>
</section>
</template>
开始
在顺序操作时并未发现问题, 且能正常释放路由:
此时使用Vue-DevTools
看到的结果是, 没有问题.
开始进行关闭
或刷新
标签页操作后, 出现了问题
居然出现了重复
的路由组件
, 并且key
相同(这里很反直觉), 经过测试该路由组件也没有正常调用Vue生命周期
内销毁
的方法, 这样会带来几个问题:
- 缓存的页面不释放, 内存可能会持续增加
- 不调用
销毁
的方法, 可能导致某些情况下业务场景不能被满足, 例如用户关闭该标签需要通知操作 - 关闭后下次打开相同ID的路由 是否会触发多次create或都不触发creatd
查阅Vue官方文档后得到一个手动销毁
当前实例的方法:
$destroy
完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。 触发 beforeDestroy 和 destroyed 的钩子
本着尽可能缩小代码影响的原则, 编写一个混合mixin
如下:
1
2
3
4
5
6
7
8
9
10
export default {
watch: {
'$route'(val) {
// 结合全局混合, 若无则使用当前路由
if (!this.$store.state.tagsView.visitedViews.find(r => r.fullPath === val.fullPath)) {
this.$destroy() // 手动触发销毁
}
},
},
}
将混合
加入到需要释放的路由组件内即可
逻辑比较简单: 当路由
发生改变
的时候, 检测Vuex
内visitedViews
, 也就是所有的标签页内是不是还有当前路由组件的路径, 如果不存在, 证明是用户关闭了, 可以手动释放该路由组件
看一下结果:
这样即便内存增加也是有释放机会的, 同时销毁
行为也能正常执行, created
也是每次使用每次触发
从代码看就能得出, 当路由切换时候才进行检测, 所以会有释放
不够及时
的问题, 如果需要及时释放, 则需setInterval
配合一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
export default {
data() {
// 缓存本组件真实的路由, 防止后续this.$route变更导致指定的对象错误
const { path, fullPath, params, query } = this.$route ? this.$route : {}
return {
ROUTE: { path, fullPath, params, query },
}
},
methods: {
checkRouterDestroy() {
// 结合全局混合, 若无则使用当前路由
if (!this.$store.state.tagsView.visitedViews.find(r => r.fullPath === this.ROUTE.fullPath)) {
window.clearInterval(this.ROUTE._EVENT) // 清除定时器
this.$destroy() // 手动触发销毁
}
}
},
watch: {
'$route': 'checkRouterDestroy',
},
cretaed() {
// 生成定时器100毫秒检测一次是否释放
this.ROUTE._EVENT = window.setInterval(this.checkRouterDestroy, 100)
},
}
这样就可以做到及时释放路由组件
, 附作用是需要100毫秒延迟
, 目的是为了减小改动范围.