云计算、AI、云原生、大数据等一站式技术学习平台

网站首页 > 教程文章 正文

vue深坑记-keep-alive 路由缓存和清除

jxf315 2024-12-27 14:12:55 教程文章 34 ℃


大家好,我是yangyang.这两天遇到了vue缓存问题,看了很多资料,才解决.然后今天就转发一篇文章

需求一:index搜索后跳转详情页面,从详情页返回保留index搜索后的样子

在app.vue里面的router-view外面包一层keep-alive include写需要缓存的页面的name (组件外面包keep-alive是必须步骤)

Keep-alive 缓存组件

<keep-alive> 是 Vue 提供的一个抽象组件,用于在组件切换时缓存组件的状态或 DOM 节点,以便在下次再次渲染时能够复用这些组件或 DOM 节点,提高性能。

当你将组件包裹在 <keep-alive> 标签内时,这个组件的状态将被保留,而不会被销毁。这样,在组件切换时,如果下次再次渲染这个被缓存的组件时,Vue 会直接复用之前缓存的状态而不是重新创建组件。

第一种(网上作者写的)

在app.vue里面的router-view外面包一层keep-alive include写需要缓存的页面的name (组件外面包keep-alive是必须步骤)

第二种(个人写)

<template>
  <div id="app">
    <div class="home">
      <!-- :key="$route.fullPath" -->
      <!-- <router-view  /> -->
      <keep-alive>
        <router-view v-if="$route.meta.keepAlive"></router-view>
      </keep-alive>
      <router-view v-if="!$route.meta.keepAlive"></router-view>
    </div>
  </div>
</template>

? 从index页面返回到最外面,再进index的时候也保留了 怎么进入index的时候消除缓存呢?所以产生下面的需求

需求2:从其他地方进入index的时候不保留缓存

使用destory destory后keep-alive不再缓存.我在index写了一个组件内的守卫

但是这么写的效果是:
刷新后初次进index,搜索-->跳转详情页面--> 返回index保留了搜索记录-->返回index再上一层页面比如导航页面-->再进index ,搜索-->跳转详情页-->返回index的时候就不保留搜索记录了

? 每次只有刷新后第一次进index才保留 这是什么原因呢?

在手动销毁组件index后,会创建另一个实例 但keep-alive不再缓存它,每次显示时都会重新创建一个新实例。
而我想要的效果 是手动销毁后,重新创建index页面并keep-alive缓存起来

include动态绑定--推荐!

include绑定一个动态数据,动态修改缓存的内容 来达到清楚缓存组件的目的,而不是直接destory

? 踩坑:在app.vue页面控制跳转到详情页的时候缓存index,用了组件内路由守卫 beforeRouteLeave

原因:因为我这个单页面应用一直在app.vue里面没离开过啊!

? 正确做法:监听$route来判断去哪里 然后改变include值

? 踩坑:我要去的是详情页面 回index首页不刷新+但是从nav页面去index的时候要清除之前的记录

那么去的name应该是详情以及index页面的路由name

include直接写死目标缓存页面,然后指定页面不缓存


比如从结果设置页面 设置完结果要刷新接口拿到最新的列表,但是缓存再不会刷新 
所以需要从result页面返回的时候强制调用一下 某些接口


//结果页面 点击保存按钮时:
  async handleSave () {
      try {
        await setResult(postDataObj)
        sessionStorage.setItem('isKeep', '/missionCenter/detail/result')  
        //此处异步套一个nexttick怕还没本地存储好就调走
        this.$nextTick(() => {
          this.$router.push({ name: 'missionCenter' })
        })
      } catch (error) {
        this.$toast.fail('设置结果失败,请稍后重试')
      }
    },
    
    
//列表页面:
  activated () {
    const arr = ['/customer/detail', '/missionCenter/detail/result']
    let form = sessionStorage.getItem('isKeep') || ''
    //判断是否从 指定页面result来,是的话再次调用 拿列表的方法   this.getDataList()去发请求
    if (arr.includes(form)) {
      this.currentId = this.$route.query.id || ''
      this.getcompleteDetail()
      this.page.pageNum = 1
      this.getDataList()
      sessionStorage.removeItem('isKeep')
    }
  },
  

个人的处理方式

通过这个作者的方法并没有得到我要的效果.然后我的需求很简单,因此,首先我用了网上另外一种常见的方式(在最上面有我个人写的),通过在route里配置meta keepAlive 属性去判断组件是否缓存.然后测试出来,返回上一页还是会渲染原来的数据,最后我通过在页面增加了一下代码:

  beforeRouteEnter(to, from, next) {
    next((vm) => {
      vm.resetForm()
    })
  },
    
 resetForm:
      this.form = Object.assign({}, defaultForm)
      this.$set(this.form, 'scenes', [])

总结

  1. 组件外包keep-alive可以缓存 避免路由跳转的重复created
  2. 钩子执行步骤
  3. 假设2个页面只写了这4个钩子函数,那么执行顺序是 跳转出去了才会执行缓存的index页面的deactivated钩子
  1. 清除缓存 可以通过动态控制include的值
  2. 可以通过监听$route来判断去哪的时候 控制include值


最近发表
标签列表