最近用VUE做商城开发遇到了一个场景,
有三个页面分别是:
1.分类页面:展示了很多入口,如手机(id:1)、电视(id:2)、耳机(id:3)、电脑(id:4)等等..
2.商品列表页:点击分类之后查询对应的商品列表
3.商品详情:点击商品列表中的商品进入详情页,查看当前商品的详细信息
目标
1.分类页面 --> 进入商品列表 商品列表展示最新数据
2.商品详情 --> 返回商品列表 商品列表展示历史数据(如:我点击的商品列表第50个商品进入详情页,点击返回后列表页还要停留在第50个的位置)
实现
首先用 keep-alive 来进行缓存,在router配置中,对商品列表对应的路由的meta里面添加keepAlive: true, 用这个属性表示这个页面需要被缓存,
// 在商品列表的路由配置添加
meta: {
keepAlive: true,
},
然后再更改App.vue文件
// 通过路由里面meta.keepAlive属性判断是否需要缓存组件
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
但是这样会让商品列表页面的被一直缓存,每次点击分类进入列表看到的永远都是一样的数据。显然只是这样处理是不行的。
后面发现被keep-alive的组件created、mounted等生命周期只能被触发一次,这个时候需要用到 keep-alive 组件的专用生命周期 activated ,每次进入被keepAlive的页面都会触发这个生命周期。
因为分类页面进入商品列表是会传递一个ID的,所以就在activated里面通过ID判断页面数据是否需要刷新
这是分类页面进入商品列表的方式
// 分类页面
// 点击分类进入商品列表 传递了一个分类ID
this.$router.push({ path: '/productlist', query: { id } });
// productlist 商品列表页面
data() {
return {
id: '', // 接收分类页面获得的不同分类ID,通过ID去查找对应的商品列表
};
},
methods: {
getdata() {
//4.获取商品列表数据...
},
},
created() {
// 1.首次加载页面时记录分类ID
this.id = this.$route.query.id;
},
activated() {
// 2.匹配当前页面缓存的ID和接收的ID是否匹配,如果不匹配就重新请求数据
if(this.$route.query.id != this.id) {
// 3.更新id
this.id = this.$route.query.id;
this.getdata();
}
},
这里最重要的就是将获取页面数据的操作放在 activated() 里面, created() 只会执行一次,用于获取id,后续是否更新页面上的数据就根据 activated 里面的if条件判断。 这个时候的逻辑就比较完善了,但是像下面的第三种的情况还是不完善。点击相同的分类不会刷新商品列表页。
1点击分类A --> 商品列表 --> 商品详情 --> 点击返回商品列表 正常缓存了商品列表没问题
2点击分类A --> 商品列表 --> 商品详情 --> 点击返回回到分类页 --> 点击分类B 正常刷新商品列表没问题
3点击分类A --> 商品列表 --> 商品详情 --> 点击返回回到分类页 --> 点击分类A 商品列表未刷新,有点问题
延续之前的思路
在分类页进入商品列表时
这是之前的跳转
// 点击分类进入商品列表
this.$router.push({ path: '/productlist', query: { id } });
将其改成
// 生成一个随机字符串
let key = Math.random().toString(36).substr(2);
// 点击分类进入商品列表,额外传递了一个key
this.$router.push({ path: '/productbrandlist', query: { id, key } });
这样就每次在分类页面进入商品列表除了传了ID之外,还传递了一个随机字符串key(其实这里的key直接用时间戳更好)
然后再改一下商品列表页
data() {
return {
id: '', // 接收分类页面获得的不同分类ID,通过ID去查找对应的商品列表
};
},
methods: {
getdata() {
//获取商品列表数据...
},
},
created() {
// 首次加载页面时记录分类ID
this.id = this.$route.query.id;
// --------这里是新加的-------
this.key = this.$route.query.key;
},
activated() {
// 匹配当前页面缓存的ID和接收的ID是否匹配,如果不匹配就重新请求数据
// --------新加key的匹配判断-------
let id = this.$route.query.id;
let key = this.$route.query.key;
if((id != this.id) || (key != this.key)){
this.getdata();
}
},
这样改了后,整个逻辑就正确了,商品详情页面返回的是缓存状态的商品列表,分类页面进入商品列表一直都是最新的商品列表。
网上查阅的类似问题,差不多都是用的 keep-alive + include,但是这种方式我用着始终有问题,不知道是我没用对,还是这种方式不适合我这种需求。
不过换一种思路将商品列表直接缓存,然后通过不同参数判断是否要重新加载数据。实现起来比较简单,也比较好理解。