vue 自定义 keepalive 组件
前一阵来了一个新的需要,要在 vue 我的项目中实现一个多开 tab 页面的性能,原本心想,这不简略嘛就是一个减少按钮重定向吗?(当然如果这么简略我就不写这个文章了)。很快写完,提交测试。测试大哥很快就提交了一个问题:” 你两个 tab 页拜访同一个链接,怎么还是个联动的呢?”。我擦,这指定是缓存的问题。
为什么会呈现这种状况呢
keep-alive
组件是应用include
exclude
这两个属性传入组件名称来确认哪些能够被缓存的
<keep-alive exclude="a,b,c" >
<router-view></router-view>
</keep-alive>
咱们在看一下
源码
,看看人家是怎么实现的(这两张图截的真难看)
<img src=”https://img2022.cnblogs.com/blog/1393523/202207/1393523-20220705171521057-2002902406.png” width=”600px” alt=”male” />
<img src=”https://img2022.cnblogs.com/blog/1393523/202207/1393523-20220705171222906-966344680.png” width=”760px” alt=”male” />
次要逻辑(直说上述代码)就是依据传入的
include
,exclude
两个属性传入数组,依据以后拜访的组件名称判断。咱们雷同链接都拜访同一个组件名称(name)雷同,第二次拜访的时候,链接指向的是同一个组件,因为应用组件的 name 作为缓存 key,此时会被认为是读取缓存操作,就会间接加载缓存并渲染,所以呈现了两个 tab 页拜访同一个链接,呈现联动状况
如何解决这个问题呢
这个比较简单之前是因为组件 name 当 key 导致的,那咱们就不应用组件的 name 作为 key 了,改为 name+tab 的 index 作为 key。
问题晓得了怎么解决呢
graph TB
id2{keepalive 是否缓存}-->id6[不须要缓存]
id6-->id5
id2-->id7[须要缓存]
id7-. 未缓存.->id3[缓存以后页面 -vuex]
id7-. 缓存过.->id4[读取缓存 -vuex]
id4-->id5[渲染页面]
id3-->id5[渲染页面]
id1[tab1 url]-->id2
id8[tab2 url]-->id2
思路有了撸代码
group-keep-alive.js
function remove(arr, item) {if (arr.length) {var index = arr.indexOf(item)
if (index > -1) {return arr.splice(index, 1)
}
}
}
function getFirstComponentChild(children) {if (Array.isArray(children)) {for (var i = 0; i < children.length; i++) {var c = children[i]
if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {return c}
}
}
}
function isDef(v) {return v !== undefined && v !== null}
function isAsyncPlaceholder(node) {return node.isComment && node.asyncFactory}
var patternTypes = [String, RegExp, Array]
export default {
name: 'keep-alive',
abstract: true,
computed: {
// 这里算是一个伪代码
// 缓存的数组 [{'tab1/ 组件名称':comp, 'tab2/ 组件名称':comp},{'tab1/ 组件名称':comp, 'tab2/ 组件名称':comp}]
cacheArray() {return this.$store.state.xxx.groupCache},
// 以后选中的分组 例:0/1/2... 这里用来读取 cache 数组的 index
groupIndex() {return this.$store.state.xxx.groupIndex}
},
created: function created() {
// 以后 tab 的缓存
const cache = this.cacheArray[this.groupIndex]
this.cache = cache || Object.create(null)
// TODO 页面初始化事件, 后续可触发初始化事件
},
destroyed: function destroyed(to, form) {// TODO 页面来到事件,后续可触发敞开事件},
render: function render() {
var slot = this.$slots.default
var vnode = getFirstComponentChild(slot)
var componentOptions = vnode && vnode.componentOptions
// check pattern
var ref$1 = this
var cache = ref$1.cache
const key = `${this.groupIndex}/${componentOptions.Ctor.options.name}`
// 存在 key 间接读取
if (cache[key]) {vnode.componentInstance = cache[key].componentInstance
} else {
// 没有进行缓存
cache[key] = vnode
}
// 写入缓存
this.$store.dispatch('setGroupCache', {cache: this.cache})
return vnode || (slot && slot[0])
}
}
如何应用
意思一下就行了
<group-keep-alive>
<router-view :key="key" />
/group-keep-alive>
// key 肯定要辨别
computed: {key() {return `${选中 index}/${fullpath}`
},
}