keep-alive+ 导航守卫让缓存更精确

1,175 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

之前已经写过Vue用keep-alive缓存组件介绍说明文章,但是还没有实际深入过。然后可以运用的例子就来了。

自己用node爬虫爬取小说章节,并提供了几个简单的node数据查询接口。然后制作了一个vue的简易小说阅读器项目(难度并不高,所以界面样式制作时间是最久😖)


组件需缓存分析

在小说阅读器中,只有三个界面:书架书籍目录,章节阅读

这三个界面之间的关系:

三页面关系.png

实际场景效果:

小说阅读器.gif

这三个界面分别是三个vue组件,按照功能的区分,需要使用到keep-alive进行缓存的界面有两个,分别是书架书籍目录,其中的章节阅读基本每次都要重新刷新

虽然也会有重复点开同一章节的情况,但是先不做考虑,在专门卡bug么

然后对这两个页面需要做的keep-alive缓存功能也是不同的。

书架界面:这是主界面,并且基本在第一次加载时所有需要的数据都已经存在,并不存在从书籍目录切换回来后数据就会改变的情况(虽然以后可能会有未读章节数据改变),所以直接整个缓存即可。

书籍目录界面:因为此界面需要获取目录数据可能会较大,如果每次都重新创建,性能消耗过大。如果是点击某一章节看书,看完返回后又重新刷新,不太合适。所以在章节阅读界面回来后,可以直接keep-alive加载缓存。但是此时,如果keep-alive不做处理单纯缓存书籍目录也会有问题。因为书架选择不同书,书籍目录就需要改变。所以此界面需要根据来源页面不同进行缓存加载。

名称不同点
书架直接加载缓存
书籍目录根据不同来源处理缓存

最终处理方案

  1. 首先需要keep-alive缓存的组件和不缓存的区分,可以在路由的index.js文件中组件添加一个keepAlive属性判断此组件是否需要缓存。

题外话:vue cli中直接用vue add router添加路由即可

路由index.png

添加好属性后,可以在主界面中这样写,需要缓存的就会自动被keep-alive包裹

<keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>

当前的效果:(可以看到书架和书籍目录界面已经缓存了一次,并且之后的切换也不会重新刷新。而阅读章节并不受影响)

全部缓存.gif

  1. 当前已经做好缓存区分了,并且对于书架来说,缓存的没有问题,那么就要对书籍目录组件单独处理了。 在vue-router中,有一个beforeRouteEnter。 这是导航守卫中的组件内守卫,参考链接:导航守卫

该导航守卫是在渲染组件的对应路由被验证钱调用,可以使用三个参数:

参数作用
to即将到达的目标,也就是当前要出现页面
from当前导航要离开的路由,就是上一个页面
next这时可选参数,因为beforeRouteEnter内不能获取this, 所以可以通过next(vm => {})的vm访问组件实例

所以可以在书籍目录组件中添加beforeRouteEnter

beforeRouteEnter: (to, from, next) => {
    // // 判断路由来源界面
    if (from.name == 'Home' | !from.name) {
        next(vm=>{
            // 从书架过来刷新数据
            vm.getAllchapterFromApi();
        });
    } else {
        next();
    }
}

这样就完成了对应的跳转缓存。 效果:

导航卫士缓存1.gif

  1. 当然,此时会看到如果在书架中连续点击两次相同书籍,就会重复刷新,那么这类重复有没有办法解决? 在我的页面跳转时,会有一个书本名称的参数传递,可以根据此来进行判断

重复刷新1.png


错误经历

其实在导航卫士和keep-alive配合使用过程中,我想试试更多的方式,结果发现都需要书籍目录组件导航卫士的配合

错误思路1

书籍目录组件中可以设置beforeRouteEnter,那么换位思考,能不能在上一个from的组件中使用beforeRouteLeave,然后发现在上一个组件中只能通过修改to.meta.keepAlive来做保证下一个组件不被缓存。

就这样写了:

beforeRouteLeave(to, from, next) {
   if (from.name == 'Home') {
       to.meta.keepAlive = false
   }
   next()
}

看上去从书架到目录已经成功了,目录没有缓存。

但是...从章节阅读界面返回到目录时又重新刷新了

错误思路1_1.gif

这样,可能会想当然的以为在阅读组件中也设置一个反向的to.meta.keepAlive = true是否可以,但结果是,书籍目录组件只会缓存第一本,书籍切换后,再返回,加载缓存时的也是第一本。

造成这个结果的原因是,缓存的组件其实本质上并没有进行更新,缓存的还是当初第一本的样子。

错误思路1_2.gif

错误思路2

在路由index.js文件中使用beforeEnter进行配置,但是还是和第一种一样,缓存仍未更新

总结

写代码的过程中,其实可以尽可能的将自己学习过的知识点应用出来。虽然有可能一个问题看起来好像有多种写法,但一种种试过去后,就发现自己想当然了。

虽然转牛角尖确实浪费时间,但是要把教训给记录下来,虽然以后自己会忘记,但是文字不会忘。