keep-alive缓存问题

问题描述:如下图,项目中的菜单需要通过左边栏打开,左边栏打开的每个菜单都有一个对应的上部tab标签,点击tab标签也可切换页面之间的跳转(实际menu菜单跳转和上部tab页跳转都是同一个路由跳转),同时点击✖可以关闭当前菜单tab页;------------需求是:我们在打开的tab页面之间切换时,页面数据需要缓存,而我们关闭或者通过左边菜单栏重新打开页面时展示的为初始新的页面.

在这里插入图片描述

解题思路1:首先想到了使用keep-alive缓存组件实例,keep-alive中的include和exclude可以使我们缓存某些组件和不缓存某些组件,

在这里插入图片描述

include根据组件的name属性来缓存组件,但是需要为每个组件都添加name属性,并且在路由信息中配置name属性(需要和组件的name值一样);当我们点击左边路由菜单时,将当前路由的name值存储在cachedViews对象中,当我们关闭tab时清除cachedViews对应的name值;此方法可以实现点击打开页面缓存数据,关闭tab页,重新打开时,重置页面,重置缓存;

解题思路2:我们可以在路由元信息meta中设置keepAlive属性,通过keepAlive为true或false来判断是否缓存;然后将所有初始keep-alive属性设置为false,当我们点击左边menu菜单时设置this.$route.meta.keepAlive=false, 点击上面的tab时设置this.$route.meta.keepAlive=true;视觉效果上我们点击tab页时可以缓存,点击左边menu菜单时,页面缓存的数据也都清除了;但是还是有问题:当点击了tab页缓存了数据后,我们点击左边menu菜单重新进入,再次点击tab页时,又出现了上次tab缓存的页面;针对以上问题,想到了关闭tab页面时销毁当前实例,调用this.$destory()销毁当前组件实例,可以销毁但是销毁后第二次keep-alive不生效;

    <keep-alive>
      <router-view v-if="$route.meta.keepAlive" /> <!-- 只缓存指定的组件 -->
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive" /> <!-- 不缓存指定的组件 -->

解题思路3 ----- ----- 最终版:因为打开的页面都需要缓存,关闭后清除缓存,想要这种效果<===>我们使用keep-alive包裹router-view,保证所有组件都缓存,当我们关闭tab时也不用销毁缓存组件,我们只需要打开左边menu菜单时重新创建当前组件实例(为keep-alive中的router-view添加key属性,每次点击左边菜单时key值++),但此时还是有问题:

假设:我们当前通过左侧menu菜单打开tab1对应key=1,点击tab2时key++,tab2对应key=2,此时来回切换tab1和tab2页面时key不变化(只有点击左侧menu菜单key值才会变化),所以此时数据被缓存满足要求;

但是当我们关闭tab1后重新打开tab1,此时key++ ,key=3,所以tab1页面被重载没有问题,但此时我们从tab1切换到tab2时,因为key=3,所以此时tab2页也会被重载,不满足要求;所以需要我们在vuex中定义一个routeMenu对象,当我们点击tab时将当前路由以及key值保存起来

即点击tab1时,routeMenu={ ‘/route1’: 1} 点击tab2时routeMenu={ ‘/route1’: 1, ‘/route2’: 2},

当我们来回切换tab页面时,从routeMenu中根据当前路由读取key值,此时tab1对应key=1,tab2对应key=2

当我们关闭tab1重新打开tab1时,此时key=3,我们在通过左侧菜单打开页面时需要根据路由信息更新vuex中的routeMenu,此时routeMenu={ ‘/route1’: 3, ‘/route2’: 2},所以此时在切换tab1和tab2时,因为tab2的key始终为2,所以没被重载,满足要求;

问题所在:当第二次切换路由时,会加载上一个路由组件的代码,但不会渲染dom。

优化:我们不需要每次点击左边导航栏菜单时都使index变化++,我们可以先判断routeMenu此对象中是否存在某个路由.存在时index++,替换routeMenu中的信息,不存在则不需要使index变化

在这里插入图片描述
---- 其他优化问题:当我们产品详情页和产品主页不在同一个路由下时,我们先打开产品详情页查看产品详情,然后我们在打开产品页修改此条产品信息,修改成功后,切换tab进入产品详情页,因为产品详情页被缓存所以不会走本身的生命周期,所以不会请求数据,导致产品详情数据不同步; --------------------解决方案如下:
(1)在每个详情页面,走keep-alive组件的生命周期,在actived中重新请求数据,但此方法需要在每个页面中都要加入此生命周期请求数据,工作量大;
(2)为每个详情页路由设置路由元信息keepAlive:false,我们在通过tab切换页面时,判断当前路由元信息是否为false,如果为false,设置router-view中的key值为当前事件戳,保证每次进入详情页面,页面都会被重载;如果路由元信息中keepAlive不为false,从保存的routeMenu对象中读取存在的key,页面不重载;

综上所属:第一种方案和第三种方案都可以实现需求,但是第一种方案比较麻烦,需要每个组件都有name属性,并且路由中添加name,且两个name值必须相等;第三种方案的问题:当第二次切换路由时,会加载上一个路由组件的代码,但不会渲染dom。不影响实际功能.

给keep-alive外面的ui-main组件设置了key,每次点击左边menu时都会重新强制刷新组件,每个缓存的组件都被刷新了—不满足;

keep-alive原理:vNode指虚拟 DOM 树中的节点

(1)当被keep-alive包裹的组件第一次被渲染时,实际上是将组件的vNode缓存起来,然后将其从Dom树中移除,并不会真正销毁组件实例.当重新渲染时,vue会从缓存中找到vNode,重新插入到Dom树种;
(2)在内部实现上,keep-alive通过一个名为cache对象来缓存vNode,cache的键由组件的 name 和 key 连接而成的字符串组成,key 是组件的唯一标识符,可以是组件的某个属性或者是一个字符串。
(3)当一个keep-alive包裹的组件被激活时,vue先根据当前的路由对应的组件名称和标识符去cache中找对应的vNode,如果找到了将vNode转化为组件实例,并挂载到Dom,如果找不到则重新创建组件实例,并将组件的vNode存储cache中.
(4)当一个被 包裹的组件离开时,Vue 会将其 VNode 从 DOM 树中移除,并不会销毁组件实例。这样,在组件再次激活时,可以直接从 cache 中获取对应的 VNode,并将其转化为组件实例并挂载到 DOM 上,而不需要重新创建组件实例和重新渲染 DOM。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值