keep-alive前进刷新后退缓存解决方案

521 阅读2分钟

场景

最近接到需求,列表页A跳转到表单页B填写内容,可能要到C页面去选择数据,填充表单页B,要求从A到B不缓存,从C返回B需要缓存

*暗自窃喜,这个简单啊,给B路由设置keepAlive=true,路由拦截,从A到BkeepAlive设置False,从C到B设置keepAlive为true,正以为大功告成时,bug光顾:

从A到B填写部分数据,跳转C选择返回,填写的数据刷新了,以为眼睛花了,再填一次,继续跳转C选数据返回,嘿,缓存了,也就是第一次没有缓存,第二次才缓存了

返回列表A页面,继续重复以上操作,奇怪现象再次出现,第一次从C返回就缓存了,但是缓存的是上面操作的数据

解决过程

项目要上线啊,用最笨的方法,在不需要缓存的时候刷新一下吧,判断是从B来到A,就router.go(0)刷新,方法是笨了点,但是可行。 如果有多个这样的页面,我都要去判断并刷新实在太麻烦,已经应付了上线,找原因吧

router.beforeEach((to, from, next) => {
  if (from.path === B && to.path === A) {
    router.go(0)
  } else {
    next()
  }
})

查看keep-alive缓存机制,维护了一个cache对象,用组件的key(没设置则自动生成)作为cache的key,vnode作为值,cache[key] = vnode,每次渲染的时候都会查看cache[key]是否有值,有则直接取cache[key]渲染

所以我们只要保证不需要缓存的组件的key不存在cache里面,就不会缓存了

<keep-alive>
  <component :is="Component" v-if="$route.meta.keepAlive" :key="$route.fullPath"/>
</keep-alive>
<component :is="Component" v-if="!$route.meta.keepAlive" />

从A跳转B的时候,带时间戳,就可以保证route.fullPath唯一,返回的时候不改变route.fullPath唯一,返回的时候不改变route.fullPath

router.push({
  path: '/B',
  query: {
    id: Date.now()
  }
})

也可以在路由守卫里面判断,to.meta.keepAlive为true,就自动带上时间戳

总结

  • 第一种方法之所以第一次不缓存,因为从A到B,没有缓存,第一次填的内容自然不会被缓存下来,从C返回B,缓存了,再填写,在返回,有内容了
  • 再次推出B返回A,重复上述操作,缓存了第一次的内容,这里没有太明白,我想应该是key和上次一样了,待深究