Vue缓存 菜单、多Tab解决方案

13,520 阅读3分钟

1.需求

在项目开发中,前端难免遇到需要路由缓存的需求。在之前一个React项目中,查询各种资料和插件后,了解到React要配合React-router进行路由缓存,会有很多意想不到的问题。所以在React项目中,我们都避免接收到需要路由缓存的需求。

最近在开发一个vue项目中,由于vue原生有Keep-alive组件以及includeexclude的各种api来实现路由缓存。所以我们决定大胆的接下这个坑。

2.踩坑

一开始我们也是直接用keep-alive包裹住router-view  加上路由的fullPath作为router-viewkey值,然后用include定义需要缓存的组件。


以及在路由定制的meta里面定义keepalive是否需要缓存字段来处理缓存


对于一般的项目,其实这样解决缓存已经可以了。但是我们是对应B端的管理系统,会有菜单页,Tab页,一个路由可能在不同的情况会需要缓存以及不需要缓存两种情况。在动态改变keepaliveList或者$route.meta.keepalive后,并没有触发组件缓存的销毁以及再缓存。所以我们只能变换方法来实现。

3.解决思路--清理详情页缓存

我们的项目会有多个Tab的形式,类似于element-ui的tabs组件。

我们在相同tab下的路由配置了相同的pageKey代表在一个tab下的路由组件。

按照上面的配置,组件A,B是在一个tab下,C是在另一个tab下的。

在用keep-alive包裹住router-view后,可以实现切换不同tab,切换路由,缓存页面,但是在同一个tab下从列表跳到详情页,我们需要详情页每次进入都需要清楚缓存重新查询数据。介于有这两种需要不同缓存效果的组件,我们在路由定义时多加了一个noCache字段,定义了这个字段的路由,表明在不同pageKey路由(表示不同tab)之间切换时,需要缓存,在相同pageKey(表示同一tab)路由之间切换时,不需要缓存并清理。

在查询资料后,了解到vue把缓存组件存储到$vnode.parent.componentInstance.cache中,我们想到了一个用vue路由钩子清理缓存的一个方法。


以上代码是在第一次打开详情页返回到列表页时,进入beforeRouteLeave钩子函数,调用clearCache方法清除详情页的缓存。

4.解决思路--关闭tab清理缓存

现在还有一个问题是每个tab会有关闭按钮,在点击一个tab的关闭按钮后,应该清除该tab同一个pageKey的所有组件缓存。这里我们在点击关闭按钮事件中设置vuex全局变量在全局beforeRouteLeave的判断里加上该判断,如果全局变量变化说明点击了关闭按钮,然后再clearCache方法内部清除相同pageKey的组件cache列表。

5.解决思路--返回列表缓存查询条件并重查数据

到这里其实大部分的缓存问题已经解决了,但是我们可爱的产品爸爸,突然给我们提了一个新的需求,在详情页跳转到列表页的时候,需要列表页的查询条件存在,并且重查一次查询。刚开始我们决定考虑新的解决思路来清理列表页的缓存,并且存储下列表页的查询条件。由于我们列表页不会设置noCache字段,所以查询列表的条件缓存是存在的,我们只需要重新调一次查询接口就可以了。

根据这个思路,我们在详情页跳转回列表页时给详情页meta对象新增一个backSearch字段,在beforeRouteLeave中如果捕获到from.meta.backSearch,则删除这个属性并且设置to.meta.backSearch=true,再设置一个全局actived缓存钩子如果检测到该路由的meta.backSearch字段,则自动调用组件定义的myOption方法实则为该组件的查询方法

6.解决思路--url随机数清理缓存

以上大概解决了业务提的所有缓存需求。但是在最近的开发中,由于用户的骚操作,又爆发出了缓存的又一bug。

我们清理详情页缓存的触发条件是,相同pageKey之间跳转的情况,例如详情页跳转回列表页,但是用户的一次操作是进入了详情页直接点击菜单进入了其他页面,然后点列表菜单重新进入列表页,路由全在不同pageKey的情况下跳转,并没有触发详情页缓存逻辑。

在注意到我们的router-view key字段是$route.fullPath,所以我们决定给url加上随机数来解决这个问题。

7.结语

目前我没找寻到一个业界比较公认的缓存解决办法,我们也在探索之中。我们的方法可能比较繁琐,但目前能解决我们的开发需求,如果有大佬能给我们提一些宝贵的意见,我们会非常感谢。