问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

vue3迫不得已我硬着头皮查看了keepalive的源代码,解决了线上的问题

发布网友 发布时间:2024-09-30 11:22

我来回答

1个回答

热心网友 时间:2024-10-06 13:38

1、通过本文可以了解到vue3keepalive功能

2、通过本文可以了解到vue3keepalive使用场景

3、通过本文可以学习到vue3keepalive真实的使用过程

4、通过本文可以学习vue3keepalive源码调试

5、通过本文可以学习到vue3keepalive源码的精简分析

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-viewv-slot="{Component}"><keep-alive:include="keepAliveCache"><component:is="Component":key="$route.name"/></keep-alive></router-view></template><scriptlang="ts"setup>import{computed}from"vue";import{useKeepAliverStore}from"@/store";constuseStore=useKeepAliverStore();constkeepAliveCache=computed(()=>{returnuseStore.caches;});</script>

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

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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";constuseStore=useKeepAliverStore()exportdefault{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)){consttop=useStore.scrollList.get(routeName)refList.value.setScrollTop(Number(top))}});onDeactivated(()=>{consttop=refList.value.getScrollTop()useStore.scrollList.set(routeName,top)});

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

constsetScrollTop=(value:any)=>{constdom=document.querySelector('.van-pull-refresh')dom!.scrollTop=value}

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

onMounted(()=>{scrollDom.value=document.querySelector('.van-pull-refresh')asHTMLElementconstthrottledFun=useThrottleFn(()=>{console.log(scrollDom.value?.scrollTop,'addEventListener')state.scrollTop=scrollDom.value!.scrollTop},500)if(scrollDom.value){scrollDom.value.addEventListener('scroll',throttledFun)}})constgetScrollTop=()=>{console.log('scrollDom.vaue',scrollDom.value?.scrollTop)returnstate.scrollTop}

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

https://vueuse.org/shared/usethrottlefn/#usethrottlefn

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

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

1、克隆代码

gitclonegit@github.com:vuejs/core.git

2、安装依赖

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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

参考https://juejin.cn/post/6991653445161713671

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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

5、执行pnpmrundev则会buildvue源码

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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、调试截图说明

9、调试操作,小视频观看

5、vue3keealive源码粗浅分析

通过查看vue3KeepAlive.ts源码,源码路径:https://github.com/vuejs/core/blob/main/packages/runtime-core/src/components/KeepAlive.ts

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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=[]}}});56、总结

通过这次查看vue3keepalive源码发现,其实也没那么难,当然这次查看源代码也只是粗略查看,并没有看的那么细,主要还是先解决问题。动动手调试一下,有时候真的就是不逼一下自己都不知道自己有多么的优秀。原来我也能稍微看看源代码了。以后有空可以多看看vue3源代码,学习一下vue3的精髓。了解vue3更为细节的一些知识点。

原文:https://juejin.cn/post/7103405860449157134

热心网友 时间:2024-10-06 13:38

1、通过本文可以了解到vue3keepalive功能

2、通过本文可以了解到vue3keepalive使用场景

3、通过本文可以学习到vue3keepalive真实的使用过程

4、通过本文可以学习vue3keepalive源码调试

5、通过本文可以学习到vue3keepalive源码的精简分析

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-viewv-slot="{Component}"><keep-alive:include="keepAliveCache"><component:is="Component":key="$route.name"/></keep-alive></router-view></template><scriptlang="ts"setup>import{computed}from"vue";import{useKeepAliverStore}from"@/store";constuseStore=useKeepAliverStore();constkeepAliveCache=computed(()=>{returnuseStore.caches;});</script>

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

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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";constuseStore=useKeepAliverStore()exportdefault{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)){consttop=useStore.scrollList.get(routeName)refList.value.setScrollTop(Number(top))}});onDeactivated(()=>{consttop=refList.value.getScrollTop()useStore.scrollList.set(routeName,top)});

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

constsetScrollTop=(value:any)=>{constdom=document.querySelector('.van-pull-refresh')dom!.scrollTop=value}

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

onMounted(()=>{scrollDom.value=document.querySelector('.van-pull-refresh')asHTMLElementconstthrottledFun=useThrottleFn(()=>{console.log(scrollDom.value?.scrollTop,'addEventListener')state.scrollTop=scrollDom.value!.scrollTop},500)if(scrollDom.value){scrollDom.value.addEventListener('scroll',throttledFun)}})constgetScrollTop=()=>{console.log('scrollDom.vaue',scrollDom.value?.scrollTop)returnstate.scrollTop}

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

https://vueuse.org/shared/usethrottlefn/#usethrottlefn

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

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

1、克隆代码

gitclonegit@github.com:vuejs/core.git

2、安装依赖

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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

参考https://juejin.cn/post/6991653445161713671

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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

5、执行pnpmrundev则会buildvue源码

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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、调试截图说明

9、调试操作,小视频观看

5、vue3keealive源码粗浅分析

通过查看vue3KeepAlive.ts源码,源码路径:https://github.com/vuejs/core/blob/main/packages/runtime-core/src/components/KeepAlive.ts

import{defineStore}from"pinia";exportconstuseKeepAliverStore=defineStore("useKeepAliverStore",{state:()=>({caches:[]asany,scrollList:newMap(),//缓存页面组件如果又滚动条的高度}),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=[]}}});56、总结

通过这次查看vue3keepalive源码发现,其实也没那么难,当然这次查看源代码也只是粗略查看,并没有看的那么细,主要还是先解决问题。动动手调试一下,有时候真的就是不逼一下自己都不知道自己有多么的优秀。原来我也能稍微看看源代码了。以后有空可以多看看vue3源代码,学习一下vue3的精髓。了解vue3更为细节的一些知识点。

原文:https://juejin.cn/post/7103405860449157134
vue3迫不得已我硬着头皮查看了keepalive的源代码,解决了线上的问题

vue3迫不得已我硬着头皮查看了keepalive的源代码,解决了线上的问题1、通过本文可以了解到vue3keepalive功能2、通过本文可以了解到vue3keepalive使用场景3、通过本文可以学习到vue3keepalive真实的使用过程4、通过本

如何防止别人修改自己的CONN与数据库?

解决方案:程序员应该在网页发布前对其进行彻底的调试;安全专家需要固定asp 包含文件以便外部的用户不能看他们。首先对 .inc文件内容进行加密,其次也可以使用 .asp 文件代替 .inc 文件使用户无法从浏览器直接观看文件的源代码。.inc文件的文件名不用使用系统默认的或者有特殊含义容易被用户猜测到的,尽量使用无规则的英...

vue实现keepalive vue keepalive原理 vuekeepalive缺点 vue中keepalive用法 vue keepalive 缓存 vuex搭配keepalive 迫不得已的己的意思 迫不得已的形容 迫不得已解释
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
...同系物官能团是什么(烷烃.烯烃.炔烃.苯及其同系物的物理性质.化学性 ... 为什么我电脑上网的时候不管我上什么网站,金山毒霸都弹出个对话框告诉我... 现在贵妇人的皮草价格多少 猎豹游览器的问题,坑爹啊。 如何写电子邮箱地址 如何调动小学二年级学生课堂学习的积极性? 孩子做事磨蹭如何处理? RTK模块只能用于高精度测量,而无法提供实时 gnss常用的三种定位模式 花卉号是什么意思? 记由css定位引起的乌龙 基于vue中对鼠标划过事件的处理方式详解 华为平板电脑微信如何截屏 什么商业银行理财利率高 什么银行存理财利息高 怎么添加电脑桌面时钟日历 梦到自己买钟是什么意思 形体舞是什么 支付宝怎么查找添加好友啊? 呼吸机基本原理和主要类型 呼吸机使用原理 梦见我的偶像骑着自行车,把我的手弄破了,我在后面追,就想让他停下来... 淘宝退款流程会影响信用分吗? 梦见老公正在睡觉 快手取消关注别人别人会知道吗? 梦里花落知多少 此情可待成追忆 只是当时已惘然 做梦做到猫是什么意思? 梦见洗毛绒玩具越洗越脏 请教一下,中间那个字是怎么打出来的,拼音读什么?谢谢 请教下韩国人姓金,是读Kim么?韩文怎么写? 我梦见我去拉大便看到下雨把便池里的大便都满出王小了什么意思?_百度... 苹果手机怎么下载足迹 解梦梦见大便还下雨 内乡高中分数线是多少? 内乡高中分数线 内乡一高分数线 如何投屏到长虹电视 win10电脑如何设置自动休眠 找不到的影子 歌词 李胜基大声呼喊罗.结婚好吗,马歌词和中文意思?不要给韩文的?OK 为了你, 不问距离 这句歌词是什么歌里的 工业盐和食用盐的区别,三大区别总结 好像是张信哲唱的一首歌其中歌词有句是我的影子和什么什么的样子 权力的游戏凛冬将至免费礼包可以在哪领 我的微信号怎么登不上去了呢? 我想问一下微信号登不上去是怎么回事 在手机上,打开下载小说得时候,手机显示“文件过大,只能打开部分内容... 为什么我下载的手机小说每次播放就会写着“文件太大”啊? 为什么我的txt模式下到手机里说文件过大 中国电信的光猫路由器一体机和无线路由器接时,路由器输出的“网口”插...