作者 RuoYi

修复三级菜单之间切换页面无法缓存的问题

  1 +<!-- @author ruoyi 20201128 支持三级以上菜单缓存 -->
1 <template> 2 <template>
2 <section class="app-main"> 3 <section class="app-main">
3 <transition name="fade-transform" mode="out-in"> 4 <transition name="fade-transform" mode="out-in">
4 - <keep-alive :include="cachedViews"> 5 + <keep-alive :max="20" :exclude="notCacheName">
5 <router-view :key="key" /> 6 <router-view :key="key" />
6 </keep-alive> 7 </keep-alive>
7 </transition> 8 </transition>
@@ -9,17 +10,119 @@ @@ -9,17 +10,119 @@
9 </template> 10 </template>
10 11
11 <script> 12 <script>
  13 +import Global from "@/layout/components/global.js";
  14 +
12 export default { 15 export default {
13 name: 'AppMain', 16 name: 'AppMain',
14 computed: { 17 computed: {
15 - cachedViews() {  
16 - return this.$store.state.tagsView.cachedViews 18 + notCacheName() {
  19 + var visitedViews = this.$store.state.tagsView.visitedViews;
  20 + var noCacheViews = [];
  21 + Object.keys(visitedViews).some((index) => {
  22 + if (visitedViews[index].meta.noCache) {
  23 + noCacheViews.push(visitedViews[index].name);
  24 + }
  25 + });
  26 + return noCacheViews;
17 }, 27 },
18 key() { 28 key() {
19 - return this.$route.path  
20 - }  
21 - }  
22 -} 29 + return this.$route.path;
  30 + },
  31 + },
  32 + mounted() {
  33 + // 关闭标签触发
  34 + Global.$on("removeCache", (name, view) => {
  35 + this.removeCache(name, view);
  36 + });
  37 + },
  38 + methods: {
  39 + // 获取有keep-alive子节点的Vnode
  40 + getVnode() {
  41 + // 判断子集非空
  42 + if (this.$children.length == 0) return false;
  43 + let vnode;
  44 + for (let item of this.$children) {
  45 + // 如果data中有key则代表找到了keep-alive下面的子集,这个key就是router-view上的key
  46 + if (item.$vnode.data.key) {
  47 + vnode = item.$vnode;
  48 + break;
  49 + }
  50 + }
  51 + return vnode ? vnode : false;
  52 + },
  53 + // 移除keep-alive缓存
  54 + removeCache(name, view = {}) {
  55 + let vnode = this.getVnode();
  56 + if (!vnode) return false;
  57 + let componentInstance = vnode.parent.componentInstance;
  58 + // 这个key是用来获取前缀用来后面正则匹配用的
  59 + let keyStart = vnode.key.split("/")[0];
  60 + let thisKey = `${keyStart}${view.fullPath}`;
  61 + let regKey = `${keyStart}${view.path}`;
  62 +
  63 + this[name]({ componentInstance, thisKey, regKey });
  64 + },
  65 + // 移除其他
  66 + closeOthersTags({ componentInstance, thisKey }) {
  67 + Object.keys(componentInstance.cache).forEach((key, index) => {
  68 + if (key != thisKey) {
  69 + // 销毁实例(这里存在多个key指向一个缓存的情况可能前面一个已经清除掉了所有要加判断)
  70 + if (componentInstance.cache[key]) {
  71 + componentInstance.cache[key].componentInstance.$destroy();
  72 + }
  73 + // 删除缓存
  74 + delete componentInstance.cache[key];
  75 + // 移除key中对应的key
  76 + componentInstance.keys.splice(index, 1);
  77 + }
  78 + });
  79 + },
  80 + // 移除所有缓存
  81 + closeAllTags({ componentInstance }) {
  82 + // 销毁实例
  83 + Object.keys(componentInstance.cache).forEach((key) => {
  84 + if (componentInstance.cache[key]) {
  85 + componentInstance.cache[key].componentInstance.$destroy();
  86 + }
  87 + });
  88 + // 删除缓存
  89 + componentInstance.cache = {};
  90 + // 移除key中对应的key
  91 + componentInstance.keys = [];
  92 + },
  93 + // 移除单个缓存
  94 + closeSelectedTag({ componentInstance, regKey }) {
  95 + let reg = new RegExp(`^${regKey}`);
  96 + Object.keys(componentInstance.cache).forEach((key, i) => {
  97 + if (reg.test(key)) {
  98 + // 销毁实例
  99 + if (componentInstance.cache[key]) {
  100 + componentInstance.cache[key].componentInstance.$destroy();
  101 + }
  102 + // 删除缓存
  103 + delete componentInstance.cache[key];
  104 + // 移除key中对应的key
  105 + componentInstance.keys.splice(i, 1);
  106 + }
  107 + });
  108 + },
  109 + // 刷新单个缓存
  110 + refreshSelectedTag({ componentInstance, thisKey }) {
  111 + Object.keys(componentInstance.cache).forEach((key, index) => {
  112 + if (null != thisKey && key.replace("/redirect", "") == thisKey) {
  113 + // 1 销毁实例(这里存在多个key指向一个缓存的情况可能前面一个已经清除掉了所有要加判断)
  114 + if (componentInstance.cache[key]) {
  115 + componentInstance.cache[key].componentInstance.$destroy();
  116 + }
  117 + // 2 删除缓存
  118 + delete componentInstance.cache[key];
  119 + // 3 移除key中对应的key
  120 + componentInstance.keys.splice(index, 1);
  121 + }
  122 + });
  123 + },
  124 + },
  125 +};
23 </script> 126 </script>
24 127
25 <style lang="scss" scoped> 128 <style lang="scss" scoped>
@@ -31,7 +134,7 @@ export default { @@ -31,7 +134,7 @@ export default {
31 overflow: hidden; 134 overflow: hidden;
32 } 135 }
33 136
34 -.fixed-header+.app-main { 137 +.fixed-header + .app-main {
35 padding-top: 50px; 138 padding-top: 50px;
36 } 139 }
37 140
@@ -41,7 +144,7 @@ export default { @@ -41,7 +144,7 @@ export default {
41 min-height: calc(100vh - 84px); 144 min-height: calc(100vh - 84px);
42 } 145 }
43 146
44 - .fixed-header+.app-main { 147 + .fixed-header + .app-main {
45 padding-top: 84px; 148 padding-top: 84px;
46 } 149 }
47 } 150 }
@@ -29,6 +29,7 @@ @@ -29,6 +29,7 @@
29 <script> 29 <script>
30 import ScrollPane from './ScrollPane' 30 import ScrollPane from './ScrollPane'
31 import path from 'path' 31 import path from 'path'
  32 +import Global from "@/layout/components/global.js";
32 33
33 export default { 34 export default {
34 components: { ScrollPane }, 35 components: { ScrollPane },
@@ -144,6 +145,7 @@ export default { @@ -144,6 +145,7 @@ export default {
144 }) 145 })
145 }) 146 })
146 }) 147 })
  148 + Global.$emit("removeCache", "refreshSelectedTag", this.selectedTag);
147 }, 149 },
148 closeSelectedTag(view) { 150 closeSelectedTag(view) {
149 this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => { 151 this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
@@ -151,12 +153,14 @@ export default { @@ -151,12 +153,14 @@ export default {
151 this.toLastView(visitedViews, view) 153 this.toLastView(visitedViews, view)
152 } 154 }
153 }) 155 })
  156 + Global.$emit("removeCache", "closeSelectedTag", view);
154 }, 157 },
155 closeOthersTags() { 158 closeOthersTags() {
156 this.$router.push(this.selectedTag) 159 this.$router.push(this.selectedTag)
157 this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => { 160 this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
158 this.moveToCurrentTag() 161 this.moveToCurrentTag()
159 }) 162 })
  163 + Global.$emit("removeCache", "closeOthersTags", this.selectedTag);
160 }, 164 },
161 closeAllTags(view) { 165 closeAllTags(view) {
162 this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => { 166 this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
@@ -165,6 +169,7 @@ export default { @@ -165,6 +169,7 @@ export default {
165 } 169 }
166 this.toLastView(visitedViews, view) 170 this.toLastView(visitedViews, view)
167 }) 171 })
  172 + Global.$emit("removeCache", "closeAllTags");
168 }, 173 },
169 toLastView(visitedViews, view) { 174 toLastView(visitedViews, view) {
170 const latestView = visitedViews.slice(-1)[0] 175 const latestView = visitedViews.slice(-1)[0]
  1 +import Vue from 'vue'
  2 +const global = new Vue()
  3 +export default global