keep-alive 的简单应用
业务场景
用户浏览某个数据列表,当数据列表数量很大或者有许多筛选/搜索条件时,点击查看详情然后返回,需要回到离开这个列表时的状态;
- 如果数据量过大,会使接口返回速度以及渲染速度变慢,导致页面出现长时间白屏或卡顿;
- 如果需要保存大量的筛选/搜索条件、分页等内容,则需要进行较为繁琐的操作(将内容进行存储或者作为参数传递)
使用 keep-alive 则可以较为简单的解决这些问题;
keep-alive 简介
keep-alive 是vue的一个内置组件包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们;并且是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
生命周期
- activated:被 keep-alive 缓存的组件激活时调用,该钩子在服务器端渲染期间不被调用;
- deactivated:被 keep-alive 缓存的组件停用时调用,该钩子在服务器端渲染期间不被调用;
tip:仅当组件被包裹在 keep-alive 中才会触发
Props (可接受的参数)
- include – 字符串或正则表达式。只有名称匹配的组件会被缓存。
- exclude – 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
- max – 数字。最多可以缓存多少组件实例。
tip:include 和 exclude prop 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示;
例子
在路由 (router) 文件中找到需要缓存的页面,在 meta 添加 一个属性 keepAlive 作为是否需要缓存的标识
// App.vue
<keep-alive :include="include">
<!-- 需要缓存的视图组件 -->
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<!-- 不需要缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive"></router-view>
复制代码
// router.js
export default new Router({
routes: [
{
path:'/',
name:'HelloWorld',
meta: {
keepAlive: true,
}
},
{
path:'/home',
name:'home',
meta: {
keepAlive: false,
}
},
]
})
复制代码
产生的问题
当页面有多个同级的数据列表,并且其中部分列表可以查看详情时,使用上面的代码会导致同级的数据列表之前进行切换也会进行缓存;
但是在实际的使用中仅在查看详情的时候需要进行缓存,在同级数据列表切换时数据是需要更新的;
需要使用 include 或者 exclude 进行处理,如下:
// App.vue
<keep-alive :include="include">
<router-view></router-view>
</keep-alive>
复制代码
// router.js
// 给路由 (router) 文件的相关页面添加一个字符 level,使用该字段区分该页面是详情页面还是数据列表页面
export default new Router({
routes: [
{
path:'/',
name:'HelloWorld',
meta: {
keepAlive: true,
level: 1,
}
},
{
path:'/home',
name:'home',
meta: {
keepAlive: false,
level: 2,
}
},
{
path:'/home2',
name:'home2',
meta: {
keepAlive: false,
level: 1,
}
},
]
})
复制代码
export default {
name: 'App',
data() {
return {
include: [],
}
},
watch: {
$route(to, from) {
console.log('to', to)
console.log('from', from)
// 方案1 根据系统,将 router 下的所以路由地址进行分级(例如设备管理(1),设备详情(2)),从 1 -> 2则进行缓存
// 实现方法 给 router 的 meta 添加 level 字段,分级如1,2,3
// 方案1---------------------------------------- start
// 如果要 to(进入) 的页面是需要 keepAlive 缓存的,把 name push 进 include数组
// if (to.meta.keepAlive) {
// if (!this.include.includes(to.name)) {
// this.include.push(to.name)
// }
// }
// if (from.meta.keepAlive && to.meta.level <= from.meta.level) { // 如果进行的是返回或者是同级跳转的操作则清空
// let index = this.include.indexOf(from.name);
// if (index !== -1) {
// this.include.splice(index, 1);
// }
// }
// 方案1------------------------------------------ end
// 方案2 直接判断从 to 跳转到 from 是否是要实现缓存的功能(例如 设备管理 -> 查看)
// 方案2---------------------------------------- start
if (to.meta.keepAlive) {
if (!this.include.includes(to.name)) {
this.include.push(to.name)
}
}
if (from.meta.keepAlive && from.name === 'HelloWorld' && to.name !== 'home') {
let index = this.include.indexOf(from.name);
if (index !== -1) {
this.include.splice(index, 1);
}
}
// 方案2---------------------------------------- end
}
}
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END