vue-router 提供了 vue 路由跳转的功能,有时候我们需要缓存上一个页面,避免重新渲染耗费时间,所以要对一些组件做缓存
keep-alive 组件
keep-alive
是 vue 内置的组件,用来缓存包裹的动态组件,当组件切换时候,不会销毁不活动的组件,他有两个属性include
和 exclude
,可以用来有条件地缓存组件,值可以是逗号分隔的字符串,正则表达式或者一个数组
<!-- 逗号分隔字符串 --><keep-alive include="a,b"> <component :is="view"></component> </keep-alive><!-- 正则表达式 (使用 `v-bind`) --><keep-alive :include="/a|b/"> <component :is="view"></component> </keep-alive><!-- 数组 (使用 `v-bind`) --><keep-alive :include="['a', 'b']"> <component :is="view"></component></keep-alive>
匹配首先检查组件自身的 name
选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。
不会在函数式组件中正常工作,因为它们没有缓存实例。
include 实现缓存
本文主要用 include
来实现前进时候组件缓存,后退时候组件销毁的功能
假如我们有一个需求,列表 -> 详情,详情 -> 列表,由于列表可能有查询,分页的功能,不需要销毁而是直接进入详情页面,这样返回就不需要重新生成新的组件导致原有的查询或者分页失效
那么只要在 keep-alive
添加 include
组件名数组,如下,PostList
文章列表组件会缓存,而文章详情就不会被缓存
<keep-alive :include="r"> <router-view></router-view></keep-alive>
在 data 里面声明需要缓存的组件名
data() { return { r: ['PostList'], };},
这样子就解决了两个页面之间的前进加载新页面,后退加载缓存页面的功能
多页面跳转和缓存
如果是多个页面的情况,相对比较复杂点,比如 a->b->c->d,首先记录一下路由的来源,比如 a->b->c,我们需要缓存的是 a 和 b,可以通过路由定义的 meta 属性来记录
{ path: '/b', meta: { from: 'a' // from组件名 }, name: 'bComponent', component: bComponent},{ path: '/c', meta: { from: 'b' // from组件名 }, name: 'cComponent', component: cComponent}
在初始化 r
属性的时候,默认 a
路由是必须缓存的,初始值为 r = ['a']
,通过监听 $route
属性来动态设置 keepAlive
的 include
属性值
app = { watch: { $route(newRoute, oldRoute) { let newRouteName = newRoute.name, // 新的路由名称 newRouteFrom = newRoute.meta.from; // 新的路由来源 let oldRouteName = oldRoute.name; // 旧的路由名称 if (newRouteName && newRouteFrom && oldRouteName) { if (newRouteFrom.toLowerCase() === oldRouteName.toLowerCase()) { // 新的路由来源和旧的路由名称相同,新的组件就缓存 this.r.push(newRouteName); } else { // 否则弹出 let removeCmp = this.r.pop(); } } else { // 防止home组件缓存被弹出 if (this.r.length > 1) { let removeCmp = this.r.pop(); } } }, },};
如果在 /b
路由的时候手动刷新页面,那么需要从 b
开始缓存,一般在最后一个路由的时候是不需要缓存的,所以在 created
或者 mounted
钩子函数里面判断
const app = { created() { // 刷新进入中间路由的情况 if (this.$route.name !== 'a' && this.$route.name !== 'd') { this.r.push(this.$route.name); } },};