vue3 keepalive线上问题怎么解决

广告:宝塔Linux面板高效运维的服务器管理软件 点击【 https://www.bt.cn/p/uNLv1L 】立即购买

vue3 keepalive线上问题怎么解决

1、keepalive功能

keepalive是vue3中的一个全局组件

keepalive 本身不会渲染出来,也不会出现在dom节点当中,但是它会被渲染为vnode,通过vnode可以跟踪到keepalive中的cache和keys,当然也是在开发环境才可以,build打包以后没有暴露到vnode中(这个还要再确认一下)

keepalive 最重要的功能就是缓存组件

keepalive 通过LRU缓存淘汰策略来更新组件缓存,可以更有效的利用内存,防止内存溢出,源代码中的最大缓存数max为10,也就是10个组件之后,就开始淘汰最先被缓存的组件了

2、keepalive使用场景

这里先假设一个场景: A页面是首页=====> B页面列表页面(需要缓存的页面)=======> C 详情页 由C详情页到到B页面的时候,要返回到B的缓存页面,包括页面的基础数据和列表的滚动条位置信息 如果由B页面返回到A页面,则需要将B的缓存页清空

上述另外一个场景:进入页面直接缓存,然后就结束了,这个比较简单本文就不讨论了

3、在项目中的使用过程

keepalive组件总共有三个参数

include:可传字符串、正则表达式、数组,名称匹配成功的组件会被缓存

exclude:可传字符串、正则表达式、数组,名称匹配成功的组件不会被缓存

max:可传数字,限制缓存组件的最大数量,默认为10

首先在App.vue根代码中添加引入keepalive组件,通过这里可以发现,我这里缓存的相当于整个页面,当然你也可以进行更细粒度的控制页面当中的某个区域组件

    <template>        <router-view v-slot="{ Component }">            <keep-alive :include="keepAliveCache">                <component :is="Component" :key="$route.name" />            </keep-alive>        </router-view>    </template>    <script lang="ts" setup>    import { computed } from "vue";    import { useKeepAliverStore } from "@/store";    const useStore = useKeepAliverStore();    const keepAliveCache = computed(() => {        return useStore.caches;    });    </script>
登录后复制

通过App.vue可以发现,通过pinia(也就是vue2中使用的vuex)保存要缓存的页面组件, 来处理include缓存,和保存页面组件中的滚动条信息数据

    import { defineStore } from "pinia";    export const useKeepAliverStore = defineStore("useKeepAliverStore", {        state: () => ({            caches: [] as any,            scrollList: new Map(),  // 缓存页面组件如果又滚动条的高度        }),        actions: {            add(name: string) {                this.caches.push(name);            },            remove(name: string) {                console.log(this.caches, 'this.caches')                this.caches = this.caches.filter((item: any) => item !== name);                console.log(this.caches, 'this.caches')            },            clear() {                this.caches = []            }        }    });
登录后复制

组件路由刚刚切换时,通过beforeRouteEnter将组件写入include, 此时组件生命周期还没开始。如果都已经开始执行组件生命周期了,再写入就意义了。

所以这个钩子函数就不能写在setup中,要单独提出来写。当然你也可以换成路由的其他钩子函数处理beforeEach,但这里面使用的话,好像使用不了pinia,这个还需要进一步研究一下。

    import { useRoute, useRouter, onBeforeRouteLeave } from "vue-router";    import { useKeepAliverStore } from "@/store";    const useStore = useKeepAliverStore()    export default {        name:"record-month",        beforeRouteEnter(to, from, next) {            next(vm => {                if(from.name === 'Home' && to.name === 'record-month') {                useStore.add(to.name)                }            });        }    }    </script>
登录后复制

组件路由离开时判断,是否要移出缓存,这个钩子就直接写在setup中就可以了。

    onBeforeRouteLeave((to, from) => {        console.log(to.name, "onBeforeRouteLeave");        if (to.name === "new-detection-detail") {            console.log(to, from, "进入详情页面不做处理");        } else {            useStore.remove(from.name)            console.log(to, from, "删除组件缓存");        }    });
登录后复制

在keepalive两个钩子函数中进行处理scroll位置的缓存,onActivated中获取缓存中的位置, onDeactivated记录位置到缓存

    onActivated(() => {        if(useStore.scrollList.get(routeName)) {            const top = useStore.scrollList.get(routeName)            refList.value.setScrollTop(Number(top))        }    });    onDeactivated(() => {        const top = refList.value.getScrollTop()        useStore.scrollList.set(routeName, top)    });
登录后复制

这里定义一个方法,设置scrollTop使用了原生javascript的api

    const setScrollTop = (value: any) => {        const dom = document.querySelector('.van-pull-refresh')        dom!.scrollTop = value    }
登录后复制

同时高度怎么获取要先注册scroll事件,然后通过getScrollTop 获取当前滚动条的位置进行保存即可

    onMounted(() => {        scrollDom.value = document.querySelector('.van-pull-refresh') as HTMLElement        const throttledFun = useThrottleFn(() => {            console.log(scrollDom.value?.scrollTop, 'addEventListener')            state.scrollTop = scrollDom.value!.scrollTop        }, 500)        if(scrollDom.value) {            scrollDom.value.addEventListener('scroll',throttledFun)        }    })    const getScrollTop = () => {        console.log('scrollDom.vaue', scrollDom.value?.scrollTop)        return state.scrollTop    }
登录后复制

上面注册scroll事件中使用了一个useThrottleFn,这个类库是@vueuse/core中提供的,其中封装了很多工具都非常不错,用兴趣的可以研究研究

    https://vueuse.org/shared/usethrottlefn/#usethrottlefn
登录后复制

此时也可以查看找到实例的vnode查找到keepalive,是在keepalive紧挨着的子组件里

    const instance = getCurrentInstance()    console.log(instance.vnode.parent) // 这里便是keepalive组件vnode    // 如果是在开发环境中可以查看到cache对象    instance.vnode.parent.__v_cache    // vue源码中,在dev环境对cache进行暴露,生产环境是看不到的    if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {        ;(instance as any).__v_cache = cache    }
登录后复制4、vue3 keepalive源码调试

1、克隆代码

    git clone git@github.com:vuejs/core.git
登录后复制

2、安装依赖

    import { defineStore } from "pinia";    export const useKeepAliverStore = defineStore("useKeepAliverStore", {        state: () => ({            caches: [] as any,            scrollList: new Map(),  // 缓存页面组件如果又滚动条的高度        }),        actions: {            add(name: string) {                this.caches.push(name);            },            remove(name: string) {                console.log(this.caches, 'this.caches')                this.caches = this.caches.filter((item: any) => item !== name);                console.log(this.caches, 'this.caches')            },            clear() {                this.caches = []            }        }    });0
登录后复制

3、如果不能使用pnpm,可以先通过npm安装一下

    import { defineStore } from "pinia";    export const useKeepAliverStore = defineStore("useKeepAliverStore", {        state: () => ({            caches: [] as any,            scrollList: new Map(),  // 缓存页面组件如果又滚动条的高度        }),        actions: {            add(name: string) {                this.caches.push(name);            },            remove(name: string) {                console.log(this.caches, 'this.caches')                this.caches = this.caches.filter((item: any) => item !== name);                console.log(this.caches, 'this.caches')            },            clear() {                this.caches = []            }        }    });1
登录后复制

4、安装完成以后,找到根目录package.json文件中的scripts

    import { defineStore } from "pinia";    export const useKeepAliverStore = defineStore("useKeepAliverStore", {        state: () => ({            caches: [] as any,            scrollList: new Map(),  // 缓存页面组件如果又滚动条的高度        }),        actions: {            add(name: string) {                this.caches.push(name);            },            remove(name: string) {                console.log(this.caches, 'this.caches')                this.caches = this.caches.filter((item: any) => item !== name);                console.log(this.caches, 'this.caches')            },            clear() {                this.caches = []            }        }    });2
登录后复制

参考 https://www.yisu.com/article/154583.htm

5、执行pnpm run dev则会build vue源码

    import { defineStore } from "pinia";    export const useKeepAliverStore = defineStore("useKeepAliverStore", {        state: () => ({            caches: [] as any,            scrollList: new Map(),  // 缓存页面组件如果又滚动条的高度        }),        actions: {            add(name: string) {                this.caches.push(name);            },            remove(name: string) {                console.log(this.caches, 'this.caches')                this.caches = this.caches.filter((item: any) => item !== name);                console.log(this.caches, 'this.caches')            },            clear() {                this.caches = []            }        }    });3
登录后复制

6、然后在 ....\core\packages\vue\examples\composition中添加一个aehyok.html文件,将如下代码进行拷贝,然后通过chrome浏览器打开,F12,找到源代码的Tab页面,通过快捷键Ctrl+ P 输入KeepAlive便可以找到这个组件,然后通过左侧行标右键就可以添加断点,进行调试,也可以通过右侧的【调用堆栈】进行快速跳转代码进行调试。

    import { defineStore } from "pinia";    export const useKeepAliverStore = defineStore("useKeepAliverStore", {        state: () => ({            caches: [] as any,            scrollList: new Map(),  // 缓存页面组件如果又滚动条的高度        }),        actions: {            add(name: string) {                this.caches.push(name);            },            remove(name: string) {                console.log(this.caches, 'this.caches')                this.caches = this.caches.filter((item: any) => item !== name);                console.log(this.caches, 'this.caches')            },            clear() {                this.caches = []            }        }    });4
登录后复制

7、调试源码发现 keepalive中的render函数(或者说时setup中的return 函数)在子组件切换时就会去执行,变更逻辑缓存

第一次进入页面初始化keepalive组件会执行一次,

然后点击组件一,再次执行render函数

然后点击组件二,会再次执行render函数

8、调试截图说明

5、vue3 keealive源码粗浅分析

通过查看vue3 KeepAlive.ts源码

    import { defineStore } from "pinia";    export const useKeepAliverStore = defineStore("useKeepAliverStore", {        state: () => ({            caches: [] as any,            scrollList: new Map(),  // 缓存页面组件如果又滚动条的高度        }),        actions: {            add(name: string) {                this.caches.push(name);            },            remove(name: string) {                console.log(this.caches, 'this.caches')                this.caches = this.caches.filter((item: any) => item !== name);                console.log(this.caches, 'this.caches')            },            clear() {                this.caches = []            }        }    });5
登录后复制

以上就是vue3 keepalive线上问题怎么解决的详细内容,更多请关注9543建站博客其它相关文章!

广告:SSL证书一年128.66元起,点击购买~~~

9543建站博客
一个专注于网站开发、微信开发的技术类纯净博客。

作者头像
admin创始人

肥猫,知名SEO博客站长,14年SEO经验。

上一篇:如何使用UniApp传递数据到服务器
下一篇:vue怎么去贴纸

发表评论

关闭广告
关闭广告