vue-router使用key属性下动态清除路由缓存解决方案

app.vue
html部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div id="home">
<div class="homeBox">
<el-container>
<el-header>
</el-header>
<el-container>
<el-main>
<div class="home-container">
<div id="home-content" class="home-content">
<keep-alive :include="cacheView">
<router-view :key="routerViewKey" />
</keep-alive>
</div>
</div>
</el-main>
</el-container>
</el-container>
</div>
</div>
</template>

script部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import {mapState} from 'vuex';
import store from '@/store';
import md5 from 'js-md5';
export default {
data() {
return {}
},
computed: {
routerViewKey() {
return md5(this.$route.fullPath)
},
...mapState({
cacheView: state => state.ViewModule.cacheView
})
}
}

hooks.js

1
2
3
4
5
6
7
8
9
10
import store from '@/store';
export default (router) => {
router.beforeEach((to, from, next) => {
if (to.meta.keepAlive) {
store.dispatch('addCacheView', to.name);
store.dispatch('setCacheViewKey', to.fullPath)
}
next();
})
}

store/modules/view

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import md5 from 'js-md5'
const state = {
cacheView: [],
cacheViewKeys: [],
tabList: []
}

const actions = {
addCacheView({commit}, viewName) {
commit('ADD_CACHE_VIEW', viewName)
},
removeCacheView({commit}, viewName) {
commit('REMOVE_CACHE_VIEW', viewName)
},
clearCacheView({commit}, viewName) {
commit('CLEAR_CACHE_VIEW', viewName)
},
setCacheViewKey({commit}, fullPath) {
commit('SET_CACHE_VIEW_KEY', md5(fullPath))
},
removeCacheViewKey({commit}, fullPath) {
commit('REMOVE_CACHE_VIEW_KEY', md5(fullPath))
},
clearCacheViewKey({commit}, fullPath) {
commit('CLEAR_CACHE_VIEW_KEY', md5(fullPath))
},
setPosition({commit}, {fullPath, position}) {
commit('SET_POSITION', {fullPath, position})
}
}

const getters = {}

const mutations = {
ADD_CACHE_VIEW(state, viewName) {
let cacheView = state.cacheView
if (!cacheView.some(item => item === viewName)) {
cacheView.push(viewName)
state.cacheView = cacheView
}
},
REMOVE_CACHE_VIEW(state, viewName) {
let cacheView = state.cacheView
let index = cacheView.findIndex(item => item === viewName)
if (index >= 0) {
cacheView.splice(index, 1)
state.cacheView = cacheView
}
},
CLEAR_CACHE_VIEW(state, viewName) {
if (viewName) {
let cacheView = state.cacheView
state.cacheView = cacheView.filter(item => item === viewName)
} else {
state.cacheView = []
}
},
SET_CACHE_VIEW_KEY(state, key) {
if (key && !state.cacheViewKeys.some(item => item === key)) {
let keyList = state.cacheViewKeys
keyList.push(key)
state.cacheViewKeys = keyList
}
},
REMOVE_CACHE_VIEW_KEY(state, key) {
if (key) {
let keyList = state.cacheViewKeys
let index = keyList.findIndex(item => item === key);
if (index >= 0) {
keyList.splice(index, 1)
state.cacheViewKeys = keyList
}
}
},
CLEAR_CACHE_VIEW_KEY(state, key) {
if (key) {
let cacheViewKeys = state.cacheViewKeys
state.cacheViewKeys = cacheViewKeys.filter(item => item === key)
} else {
state.cacheViewKeys = []
}
},
SET_POSITION(state, {fullPath, position}) {
let list = state.tabList
state.tabList = list.map(item => {
if (item.fullPath === fullPath) {
item.position = position
}
return item
})
}
}

export default {
namespace: true,
state,
actions,
getters,
mutations
}

cache-view.js

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import {mapState} from "vuex";
import md5 from 'js-md5';
import store from "@/store";
const CacheViewMixin = {
data() {
return {
routerKey: '',
fullPath: '',
keepAlive: false
}
},
methods: {
setCacheTab(menu, subMenu, fullPath) {
store.dispatch('setTab', {
menu,
subMenu,
fullPath
})
},
destroyPage() {
store.dispatch('removeCacheViewKey', this.fullPath);
},
destroyInstance() {
if (this.$vnode && this.$vnode.data.keepAlive) {
if (this.$vnode.parent
&& this.$vnode.parent.componentInstance
&& this.$vnode.parent.componentInstance.cache) {
if (this.$vnode.componentOptions) {
var key = this.routerKey
// ? this.$vnode.componentOptions.Ctor.cid +
// (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
// : this.$vnode.key;
var cache = this.$vnode.parent.componentInstance.cache;
var keys = this.$vnode.parent.componentInstance.keys;
if (cache[key]) {
if (keys.length) {
var index = keys.indexOf(key);
if (index > -1) {
keys.splice(index, 1);
}
}
delete cache[key];
}
}
}
}
this.$destroy();
}
},
computed: {
...mapState({
cacheViewKeys: state => state.ViewModule.cacheViewKeys
})
},
watch: {
// 监听缓存的列表,如果当前的routerKey不存在则销毁组件实例
cacheViewKeys(val) {
if (!val.some(item => item === this.routerKey)) {
this.destroyInstance();
}
}
},
created() {
this.fullPath = this.$route.fullPath
this.keepAlive = this.$route.meta.keepAlive;
this.routerKey = md5(this.$route.fullPath);
},
beforeRouteUpdate(to, from, next) { // 在重用的组件里调用 beforeRouteUpdate
if (from.name === to.name) {
let scrollTop = document.getElementById('home-content').scrollTop
store.dispatch('setPosition', {position: scrollTop, fullPath: from.fullPath})
}
next();
},
beforeRouteLeave(to, from, next) { // 保存滚动位置
if (to.name !== from.name) {
let scrollTop = document.getElementById('home-content').scrollTop
store.dispatch('setPosition', {position: scrollTop, fullPath: from.fullPath})
}
next();
},
activated() { // 组件挂载后调用
let tabList = store.state.ViewModule.tabList
let tab = tabList.find(item => item.fullPath === this.$route.fullPath)
if (tab && tab.hasOwnProperty('position')) {
document.getElementById('home-content').scrollTop = tab.position
}
}
}

export default CacheViewMixin;