核心思想
- 使用keep-alive缓存页面信息
- 由于vue3中keep-alive只能通过组件名称缓存,每次都会动态创建一个新的组件包装下页面
- 每次路由前进时会根据路由的深度分配一个uuid并缓存,然后用此uuid创建一个动态组件包装页面
- 此方法可以解决a->b->a->c 然后后退 c->a->b->a的问题
PageKeepAlive组件源码
vue
复制代码
<template>
<keep-alive :include="include">
<component v-if="node" :is="node" :key="data.cid" />
</keep-alive>
</template>
<script setup>
import { uuid } from '@/common/utils/StringUtil'
import { defineComponent, computed, reactive, nextTick } from 'vue'
import {useRouter} from 'vue-router'
const props = defineProps(['data'])
const router = useRouter()
const comp_cache = reactive({})
const position_cache = reactive({})
const include = computed(()=>{
let target = []
let expired = new Set(Object.keys(comp_cache))
for (let cache of Object.values(position_cache)) {
target.push(cache.cid)
expired.delete(cache.cid)
}
nextTick(()=>{ // 删除过期的缓存
for (let cid of expired) {
delete comp_cache[cid]
}
})
return target
})
const node = computed(()=>{
let data = props.data
if(!data || !data.cid || !data.comps) return null
if (!comp_cache[data.cid]) {
comp_cache[data.cid] = defineComponent({
name: data.cid,
setup() {
return () => data.comps
}
})
}
return comp_cache[data.cid]
})
router.afterEach((to) => {
let current = window.history.state.position
let path = to.path
for (let i of Object.keys(position_cache)) {
let cache = position_cache[i]
if (i > current) { // 大于当前位置的缓存清理掉
delete position_cache[i]
}
if (i == current && cache.path != path) { // replace需要去掉缓存
delete position_cache[i]
}
}
let cache = position_cache[current]
if (!cache) {
position_cache[current] = cache = {
cid: `comp_${uuid()}`,
path
}
}
to.meta.cid = cache.cid
})
</script>
使用方式
vue
复制代码
<router-view v-slot="{ Component, route }">
<PageKeepAlive :data="{cid: route.meta.cid, comps: Component}" />
</router-view>