x2IlJjmV9

23朵毒蘑菇

完美解决vue3 keep-alive多个路由使用同一个组件的缓存问题

之前页面少的话 用keep-live结合router-view,使用keep-live的include属性就可以自己决定keep-live缓存那些组件不缓存那些组件,直到遇到个问题。

vue3|vue-router

2023-05-26 16:31:21 已有版本 1 个 show:1.29kTYPE: blog

之前页面少的话 用keep-live结合router-view,使用keep-live的include属性就可以自己决定keep-live缓存那些组件不缓存那些组件,直到遇到个问题。

平时写的代码如下:

    <router-view v-slot="{ Component, route }">

        <keep-alive :include="[...visitedViewPaths]">

            <component 

              :is="Component"/>

        </keep-alive>

    </router-view>

其中 visitedViewPaths表示的是一个放Component name的数组,可以去看文档 https://cn.vuejs.org/guide/built-ins/keep-alive.html#include-exclude

如果配置的路由A用A组件,路由B用A组件,因为include属性是靠组件的name来决定缓存与不缓存的,还有这种情况,路由里配置的{ path: '/users/:id', component: User },这样的配置也是多个路由使用同一个组件的情况,现在这种路由对应的组件实例name是相同的,这就不好处理了,想到的解决方案如下:

    <router-view v-slot="{ Component, route }">

        <keep-alive :include="[...visitedViewPaths]">

            <component 

              :is="formatComponentInstance(Component,route)"/>

        </keep-alive>

    </router-view>
  
    function formatComponentInstance(){
        component.type = {
            ...component.type,
            name:route.path,
        };
        return component;
    }

为什么要这么写,因为主要原因就是改个name的嘛,component.type放的是该组件对象,不能直接改,两个component.type所指向的对象是同一个,所以用一个新对象来。
以为解决了,结果报错,报啥错就不说了,我觉得应该是vue用那个弱引用map把组件对象当作key,存了一个其他数据,对象变了就取不到该数据了。
以为没法解决了,结果百度到了一个方法完美解决 https://blog.csdn.net/qq_42611074/article/details/127206469

思路还是一样,改组件name,这次不是改原组件name,直接新建一个组件出来,如下:

<router-view v-slot="{ Component, route }">
    <keep-alive :include="[...visitedViewPaths]">
        <component 
            :is="formatComponentInstance(Component,route)"/>
    </keep-alive>
</router-view>

// 用来存已经创建的组件
const wrapperMap = new Map();
// 将router传个我们的组件重新换一个新的组件,原组件包里面
function formatComponentInstance(component, route) {
    let wrapper;
    if (component) {
        const wrapperName = route.path;
        if (wrapperMap.has(wrapperName)) {
            wrapper = wrapperMap.get(wrapperName);
        } else {
            wrapper = {
                name: wrapperName,
                render() {
                    return h(component);
                },
            };
            wrapperMap.set(wrapperName, wrapper);
        }
        return h(wrapper);
    }
}

其中 visitedViewPaths 是你自己的需要缓存的name列表,现在组件名字由你控制了,就已经解决了
多谢原文章大佬,https://blog.csdn.net/qq_42611074/article/details/127206469
总算是解决了这个疑难问题哇