项目开发中在用户由分类页category进入detail需保存用户状态,查阅了Vue官网后,发现vue2.0提供了一个keep-alive组件。
上一篇讲了keep-alive的基本用法,现在说说遇到的坑。
先说项目中的配置
在App.vue中的设置
在router中增加配置meta
上面这个设置后发现问题了,从category进入detail页后,状态被保存了,返回的时候保存了用户状态,达到了预期效果
但问题在于但从category返回到index后,再由index进入category时依然显示是缓存中的页面,此刻页面没有刷新。
返回index后的组件显示如下:
分析从index再次进入category时,直接读取了缓存的里的页面。
头大。。。。。。。我的目标只是缓存从category进入detail页面,其他的时候不缓存。
解决方案
在category中启用beforeRouteLeave钩子函数
beforeRouteLeave中只有从category进入detail时才进行缓存,其他页面都讲category的keepalive设置成false,并销毁此category组件;
然而,发现新的问题。。。。。。
第一次操作index--> category ---> detail的时候是理想效果,但当第二次操作返回index后,进行index --> category --> detail --> category时,发现缓存的对象又不对了,从detail返回category时,保存是的第一次进入detail的分类情况。
此刻category的组件显示如下
无奈。。。。。对比了第一次和第二次进入页面情况
根据vue-router提供的守卫可在路由中启用afterEach路由守卫,在afterEach中进行判断是否第一次进入,非第一次进入页面情况强制刷新一次category页面。
以上是我查看的网上解决问题的灵感文章,下面是我再开发中遇到问题的解决过程: (遇到相同问题的小伙伴可以参考下)
一、需求描述
a. 列表页(A)、新增表单页(B)、选择车位号列表页(C)
b . 首先从A跳到B,B是不需要缓存的
c. 从B跳到C,B需要缓存保存之前填写的form表单的所有内容
(我这边还有一个编辑页,需要公用B页面,只是把内容回显到B页面而已,后面再续写如何回显B,第一次的进入的时候回显,C再跳到B则不需要回显,只需缓存了)
二、解决思路
a. B路由设置keep-alive: true, 另外增加一个isIndex: false, 用来判断是否需要清缓存,从列表页A跳进来就要清,C页面跳进来则不需要清
b. 弄清楚mounted, actived, deactived 三个周期函数的执行过程
组件设置了keep-alive缓存,第一次进来的时候会执行mounted, actived,第二次进入时只会执行actived,不会执行mounted函数了,离开的时候都会执行deactived
必须要清楚这块,不然清缓存会很痛苦的
三、解决过程及部分代码结果
rounte.js
{ path: '/newMonthApply', // 月卡申请新增 name: 'newMonthApply', component: () => import('../views/monthCarApplication/newMonthApply.vue'), meta: { title: '开通月卡申请', keepAlive: true, isIndex: false, // 用来清从列表页进入的缓存 isEdit: false // 用来判断是不是当前页是不是编辑页,回显数据 } },
index.vue (A列表页)
beforeRouteLeave(to, from, next) { if (to.name == 'newMonthApply') { to.meta.isIndex = true // 设置inIndex = tre } next(); },
newMonthApply.vue (B页面)
beforeRouteEnter (to, from, next) { next(vm => { //因为当钩子执行前,组件实例还没被创建 // vm 就是当前组件的实例相当于上面的 this,所以在 next 方法里你就可以把 vm 当 this 来用了。 console.log(vm);//当前组件的实例 if (from.name == 'monthCarApplyDetal' && to.name == "newMonthApply") { to.meta.title = "编辑月卡申请" } // 为div元素重新设置保存的scrollTop值 document.querySelector('.recordContent').scrollTop = vm.scrollY }); }, //记录离开时的位置 beforeRouteLeave (to, from, next) { //保存滚动条元素div的scrollTop值 this.scrollY = document.querySelector('.recordContent').scrollTop console.log('离开时保存滚动条的位置', this.scrollY) next() }, mounted() { this.textSize = 0 if (this.$route.query.row != undefined) { console.log('===========编辑申请表单信息==============') this.rowData = JSON.parse(this.$route.query.row) // this.carsInfo = JSON.parse(this.$route.query.carsInfo) console.log('rowData', this.rowData) this.editDataHandle(this.rowData) } else { console.log('===========新增申请表单信息监听2==============') this.resetForm() } this.$nextTick(()=>{ this.box = document.querySelector('.recordContent') this.box.addEventListener('scroll', function(){ this.scrollY = document.querySelector('.recordContent').scrollTop console.log("scrollY", this.scrollY) }, false) }) }, activated() { console.log('this.$route.meta.isIndex', this.$route.meta.isIndex) if (this.$route.meta.isEdit) { // 从编辑页进去的话需要需要从新填写表单信息 if (this.$route.query.row != undefined) { console.log('===========编辑申请表单信息==============') this.rowData = JSON.parse(this.$route.query.row) // this.carsInfo = JSON.parse(this.$route.query.carsInfo) console.log('rowData', this.rowData) this.editDataHandle(this.rowData) } else { console.log('===========新增申请表单信息监听2==============') this.resetForm() } } if (this.$route.meta.isIndex) { //从首页进入,不需要缓存 this.resetForm() // console.log('rowData', this.rowData) } },
车位号搜索页.vue (C页面)
// 从车位页返回主页时把主页的keepAlive值设置为true(要做个判断,判断是不是返回到主页的) beforeRouteLeave (to, from, next) { if (to.name === 'newMonthCard' || to.name === 'monthCarModify' || to.name === 'newFreeCard' || to.name === 'freeCarModify' || to.name === 'newMonthApply' || to.name === 'newFreeApply') { // 需要缓存 to.meta.isIndex = false to.meta.isEdit = false } next() },