「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战」
前提
当我们正在商品列表浏览商品,浏览了很长一段的商品,然后点击切换到其他页面了,再次点击回到商品列表页面,还在之前浏览的地方,类似这种功能是怎么实现的呢?
我们想到了vue官网提供的keep-alive的方法(一种内部封装好的组件)。
官网介绍: keep-alive只能包裹在封装的组件中,而不能直接包裹在类似div、h1等原生标签上,那么我们要想保持状态,就得把那部分封装在一个功能性的组件上。
keep-alive是vue2.0加入的一个特性, 能缓存某个组件,或者某个路由。它的好处:
- 节省性能消耗,避免一个组件频繁重新渲染,节省开支
- 保存用户状态,比如说:我们在填写收货地址的页面,需要跳转到另一个页面通过定位选择地址信息再返回继续填写,这时候需要缓存收货地址页面,避免跳转页面导致用户数据丢失。
实现方法
1. hack手法
- 利用
meta.keeAlive字段来进行判断,
// 首页
{
path: '/',
name: 'Home',
component: Home,
meta: {
keepAlive: true
}
},
// 列表
{
path: '/list',
name: 'List',
component: List,
meta: {
keepAlive: true
}
},
// 详情
{
path: '/detail',
name: 'Detail',
component: Detail,
meta: {
keepAlive: true
}
}
- 进入到
[app.vue]页面中我们为<router-view>添加一个key,这个key就像是我们使用v-for循环所定义的一样,将key的作为一个标识,作用于vue在虚拟 dom 进行diff算法,提高渲染效率。
<template>
<div id="app">
<keep-alive>
<router-view v-if="$route.meta.keepAlive" :key="key" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" :key="key" />
</div>
</template>
<script>
export default {
computed: {
key() {
return this.$route.fullPath;
}
}
};
</script>
- 然后我们对其需要强制刷新的页面参数里加个时间戳,这样就可以实现按需
keep-alive了。
onClick() {
this.$router.push({
path: '/product',
query: {
t: +new Date()
}
})
}
meta 路由元信息
使用 vue-router 提供的 meta 对象,给需要缓存如首页、列表页、商详等添加一个字段,用来判断用户是前进还是后退以及是否需要 keep-alive
-
首先我们需要在
router.js的meta对象里定义两个值:-
keepAlive:这个路由是否需要缓存 -
deepth:深度,也就是页面之间的前进后退的层次关系
// 首页 { path: '/', name: 'Home', component: Home, meta: { keepAlive: true, deepth: 1 } }, // 列表 { path: '/list', name: 'List', component: List, meta: { keepAlive: true, deepth: 2 } }, // 详情 { path: '/detail', name: 'Detail', component: Detail, meta: { keepAlive: true, deepth: 3 } } -
-
然后我们在
app.vue中根据 meta 对象定义一下:
<div id="app">
<keep-alive :include="include">
<router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" />
</div>
- 最后我们需要实时的监听路由
data() {
return {
include: []
};
},
watch: {
$route(to, from) {
// 如果要to(进入)的页面是需要keepAlive缓存的,把name push进include数组中
if (to.meta.keepAlive) {
!this.include.includes(to.name) && this.include.push(to.name);
}
// 如果 要 form(离开) 的页面是 keepAlive缓存的,
// 再根据 deepth 来判断是前进还是后退
// 如果是后退:
if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
const index = this.include.indexOf(from.name);
index !== -1 && this.include.splice(index, 1);
}
}
},
主要步骤其实两步:设置meta、监听路由并判断。
这里有一定要注意的是:你的路由中定义的 name 和页面中定义的 name 一定要全等,并区分大小写!!!
对比
-
两者相比,第1种更加的实用,比一种简单,但是样式有点不太美观,因为路由中会带时间戳字符串;
-
第2种算是比较完美,设置起来也不难,只是对团队人员的规范性要求比较高。