作者:waker前言业务中经常会有这样的需求。页面跳转时,保留上一页的状态和数据,方便返回时处理。比如:A->B需要缓存,A->C不需要缓存。网上的例子大部分都是需要和业务组件打交道的。感觉很不合理,所以把处理此类问题的功能分享出来。Vue的keepAlive组件很适合解决这类问题,但还是有缺陷。例如,很难根据路由灵活控制是否需要缓存,只能简单的用include来匹配是否需要缓存。完成后要求如下:1.组件可以缓存在部分页面,如果脱离了这部分页面,缓存会被清理2.组件可以全局缓存3.最好是从架构层面解决,不干扰业务组件的总体思路是在路由meta中添加keepalive:['routingname']来判断页面的效果。设置一个store绑定keepalive。在全局路由钩子中,store处理代码如下。在路由meta中设置keepAlive表示访问这些页面需要缓存组件//路由配置{path:'xxx',name:'xxx',component:()=>import('xxx'),meta:{title:'xxx',keepAlive:['routingname','b'],//scope:缓存保留在这些页面上},},store中设置keepAliveIncludes绑定keepAlive//vuex设置和删除缓存组件state:{keepAliveIncludes:[]},mutations:{//设置缓存SET_KEEPALIVEINCLUDES:(state,data)=>{consthas=state.keepAliveIncludes.find(i=>i.path===data.path)if(!has){state.keepAliveIncludes.push(data)}},//删除缓存DELETE_KEEPALIVEINCLUDES:(state,data)=>{state.keepAliveIncludes=state.keepAliveIncludes.filter(i=>i.always)}},//业务页面,使用keepAlive组件这样keepAliveIncludes就绑定了keepalive组件,因为keepAlive组件内部订阅了include,所以我们不需要考虑如何删除已有的缓存,我们只需要处理keepAliveIncludes的值,组件会帮我们删除处理keepAliveIncludes的全局路由钩子//路由钩子router.beforeEach((to,from,next)=>{//取出所有缓存页面的keepalive并展平themletcachePath=store.state.keepAliveIncludes.map(i=>i.keepAlive).flat(Infinity)//清除所有非驻留缓存组件if(!cachePath.includes(to.name)){//console.log('转到未缓存的页面');store.commit('DELETE_KEEPALIVEINCLUDES')}if(to.meta.keepAlive){//constcomponentsName=to.matched[to.matched.length-1].components.default.namestore.commit('SET_KEEPALIVEINCLUDES',{path:`${to.name}`,componentName:to.name,//需要路由名称和默认组件名称始终保持不变:to.meta.keepAlive.length===0,keepAlive:to.meta.keepAlive,})}})首先开始执行流程。发现keepAlive缓存方法在router.beforeEach之前执行。失败后,我改变主意,先把组件缓存起来,然后检查是否匹配,如果不匹配,则删除已有的缓存。中间还遇到了keepAlive这个坑。vue官网没有缓存。后面组件运行的API,于是上网查了很多资料,发现keepAlive订阅了include。只要include发生变化,不在include中的缓存组件也会被清除。附录这个功能还是有缺陷的。这个方法需要默认。路由组件的名字和路由列表的名字是一致的,因为keepAlive的include命令接收到的值是组件名,而我们使用的是异步加载组件,所以在router.beforeEach的时候,组件还没有被实例化,并且没有办法获取组件当然如果是同步加载组件的话可以使用下面的代码获取组件的名称to.matched[to.matched.length-1].components.default。name如果有人知道如何解决,欢迎留言讨论