vue中如何使用keep-alive动态删除已缓存组件
导读:本文共4350字符,通常情况下阅读需要15分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要:本文小编为大家详细介绍“vue中如何使用keep-alive动态删除已缓存组件”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue中如何使用keep-alive动态删除已缓存组件”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。项目场景在做后台管理系统的时候,有这样一个需求:后台的界面如下:点击左边的菜单,会在右边的顶部生成一个个tag导航标签。当打开多个tag页时,用户... ...
目录
(为您整理了一些要点),点击可以直达。本文小编为大家详细介绍“vue中如何使用keep-alive动态删除已缓存组件”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue中如何使用keep-alive动态删除已缓存组件”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
项目场景
在做后台管理系统的时候,有这样一个需求:
后台的界面如下:
点击左边的菜单,会在右边的顶部生成一个个tag导航标签。当打开多个tag页时,用户可以在多个tag之间进行切换。需要在新增,修改页面切换tag时候,保留之前的信息,不进行页面的刷新。
问题描述
经过查询vue文档,可以使用keep-alive实现标签路由缓存,实现方式如下:
在路由配置的meta中添加keepAlive,如下:
{path:'/actdebt',component:Layout,redirect:'/actdebt/add',children:[{path:'add',name:'XXX新增配置',meta:{keepAlive:true,},component:()=>import(/*webpackChunkName:"page"*/'@/views/bankact/actdebt/add')}]},
然后在页面中使用v-if做判断,并且加上key
<keep-alive><router-view:key="$route.fullPath"class="avue-view"v-if="$route.meta.keepAlive"/></keep-alive><router-viewclass="avue-view"v-if="!$route.meta.keepAlive"/>
使用上面这种方式解决了修改不同记录的缓存问题,因为不同记录的fullPath 不一样,这样的话key就会不一样。
但是对于新增和修改同一条记录还是有缓存问题。例如新增一条记录保存成功后,下次在打开新增页面,还是缓存有之前的记录。
修改页面也是的,修改同一条记录保存成功后,再次打开可能还是会有之前的修改数据。
解决方案
要解决上面这种问题我想到的解决方案为:在不同的tag导航栏切换的时候,保留缓存数据。当关闭tag导航栏或者关闭页面的时候,清除缓存。
清除缓存可以在组件里面的deactivated钩子函数调用this.$destroy();但是发现下次打开这个页面的时候,新的组件不会被缓存了。
可以利用keep-alive的include,新打开标签时,把当前组件名加入到include数组里,关闭标签时从数组中删除关闭标签的组件名就可以了。
Include里面的值必须和组件的name属性保持一致,如下:
但是如果我同一个组件加载了两次,一个需要缓存,一个不需要缓存。但是他们的name却是一样的,还是无法解决问题。
所以是否可以重写keep-alive源码,使include可以按照路由地址匹配,而不是按照组件的name匹配。完整的代码如下:
新建keepAlive.js文件
/***base-keep-alive主要解决问题场景:多级路由缓存*前提:保证动态路由生成的routename值都声明了且唯一*基于以上对keep-alive进行以下改造:*1.组件名称获取更改为路由名称*2.cache缓存key也更改为路由名称*3.pruneCache*/const_toString=Object.prototype.toStringfunctionisRegExp(v){return_toString.call(v)==='[objectRegExp]'}exportfunctionremove(arr,item){if(arr.length){constindex=arr.indexOf(item)if(index>-1){returnarr.splice(index,1)}}}/***1.主要更改了name值获取的规则*@param{*}opts*/functiongetComponentName(opts){//returnopts&&(opts.Ctor.options.name||opts.tag)returnthis.$route.path}functionisDef(v){returnv!==undefined&&v!==null}functionisAsyncPlaceholder(node){returnnode.isComment&&node.asyncFactory}functiongetFirstComponentChild(children){if(Array.isArray(children)){for(leti=0;i<children.length;i++){constc=children[i]if(isDef(c)&&(isDef(c.componentOptions)||isAsyncPlaceholder(c))){returnc}}}}functionmatches(pattern,name){if(Array.isArray(pattern)){returnpattern.indexOf(name)>-1}elseif(typeofpattern==='string'){returnpattern.split(',').indexOf(name)>-1}elseif(isRegExp(pattern)){returnpattern.test(name)}/*istanbulignorenext*/returnfalse}functionpruneCache(keepAliveInstance,filter){const{cache,keys,_vnode}=keepAliveInstancefor(constkeyincache){constcachedNode=cache[key]if(cachedNode){//------------3.之前默认从router-view取储存key值,现在改为路由name,所以这里得改成当前key//constname=getComponentName.call(keepAliveInstance,cachedNode.componentOptions)constname=keyif(name&&!filter(name)){pruneCacheEntry(cache,key,keys,_vnode)}}}}functionpruneCacheEntry(cache,key,keys,current){constcached=cache[key]if(cached&&(!current||cached.tag!==current.tag)){cached.componentInstance.$destroy()}cache[key]=nullremove(keys,key)}constpatternTypes=[String,RegExp,Array]exportdefault{name:'keep-alive',//abstract:true,props:{include:patternTypes,exclude:patternTypes,max:[String,Number]},created(){this.cache=Object.create(null)this.keys=[]},destroyed(){for(constkeyinthis.cache){pruneCacheEntry(this.cache,key,this.keys)}},mounted(){this.$watch('include',val=>{pruneCache(this,name=>matches(val,name))})this.$watch('exclude',val=>{pruneCache(this,name=>!matches(val,name))})},render(){constslot=this.$slots.defaultconstvnode=getFirstComponentChild(slot)constcomponentOptions=vnode&&vnode.componentOptionsif(componentOptions){//checkpatternconstname=getComponentName.call(this,componentOptions)//----------对于没有name值得设置为路由得name,支持vue-devtool组件名称显示if(!componentOptions.Ctor.options.name){vnode.componentOptions.Ctor.options.name}const{include,exclude}=thisif(//notincluded(include&&(!name||!matches(include,name)))||//excluded(exclude&&name&&matches(exclude,name))){returnvnode}const{cache,keys}=this//-------------------储存的key值,默认从router-view设置的key中获取//constkey=vnode.key==null//?componentOptions.Ctor.cid+(componentOptions.tag?`::${componentOptions.tag}`:'')//:vnode.key//-------------------2.储存的key值设置为路由中得name值constkey=nameif(cache[key]){vnode.componentInstance=cache[key].componentInstance//makecurrentkeyfreshestremove(keys,key)keys.push(key)}else{cache[key]=vnodekeys.push(key)//pruneoldestentryif(this.max&&keys.length>parseInt(this.max)){pruneCacheEntry(cache,keys[0],keys,this._vnode)}}vnode.data.keepAlive=true}returnvnode||(slot&&slot[0])}}
然后在main.js中引入该组件,使组件可以全局使用
在页面直接使用BaseKeepAlive:
<BaseKeepAlive:include="cachetags"><router-view:key="$route.fullPath"class="avue-view"/></BaseKeepAlive>
cachetags 方法就是新打开标签时,把当前组件名加入到include数组里,关闭标签时从数组中删除关闭标签,源码如下:
computed:{...mapGetters(['isLock',"tagList",'isCollapse','website']),cachetags(){letlist=[]for(letitemofthis.tagList){if(!validatenull(item.keepalive)&&item.keepalive){list.push(item.value)}}returnlist.join(',')}},
方法中的tagList就是导航栏当前打开相应的tag集合如下图所示
读到这里,这篇“vue中如何使用keep-alive动态删除已缓存组件”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。
vue中如何使用keep-alive动态删除已缓存组件的详细内容,希望对您有所帮助,信息来源于网络。