• Vue 移动端(H5)项目怎么实现页面缓存(即列表页面进入详情返回后列表页面缓存且还原页面滚动条位置)keep-alive缓存及清除keep-alive缓存


    一、需求

    产品要求:Vue移动端项目进入列表页,列表页需要刷新,而从详情页返回列表页,列表页则需要缓存并且还原页面滚动条位置

    二、实现思路

    1、使用Vue中的keep-alive组件,keep-alive提供了路由缓存功能

    2、因为我项目只是针对某几个列表页面做缓存,我就直接把指定的几个页面单独的做处理(即:把需要做缓存的页面路由的meta新增了keepAlive属性,当keepAlive为true时缓存,为false则不缓存),从而实现进入列表页,列表页需要刷新,而从详情页返回列表页,列表页则需要保持页面缓存

    建议使用keep-alive includes属性来做缓存页面

    三、最终效果

    在这里插入图片描述

    四、具体实现

    1、app.vue文件修改

    <template>
      <div id="app">
        <keep-alive>
          <router-view class="Router" v-if="$route.meta.keepAlive">router-view>
        keep-alive>
        <router-view class="Router" v-if="!$route.meta.keepAlive">router-view>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2、在动态路由生成后初始化指定缓存页面路由设置metakeepAlive属性为true

    在这里插入图片描述

    3、单个列表页面的缓存处理(详情返回到列表滚动条的位置)

    beforeRouteLeave(to, from, next) {
        // console.log('777---', from)
        this.scroll = document.querySelector('.endInfo').scrollTop
        // 离开页面时,需要清除缓存(为了下次进入后刷新页面)
        from.meta.keepAlive = false
        next()
      },
      activated() {
       // 注意`endInfo`类是:列表box的顶级类,用来计算滚动条的距离
        document.querySelector('.endInfo').scrollTop = this.scroll
        console.log('缓存页面距离', this.scroll)
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4、从详情页面返回到列表,需要如下设置(关键步骤)

    beforeRouteLeave(to, from, next) {
        console.log('支付单详情页', to)
        // 设置下一个路由的meta,让列表页面缓存,即不刷新(即:此详情页面返回到sell和customerMangement页面后此页面缓存)
        if (to?.path?.includes('sell') || to?.name?.includes('customerMangement')) {
          to.meta.keepAlive = true
        }
        next()
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    五、缺陷:按此方法缓存页面,会出现列表新增数据后进入详情在返回到列表时,之前新增的数据没有(即还是上一次的缓存列表数据)

    六、解决方法:在离开列表页面就手动清除keep-alive缓存

    1、在app.vue页面加上clearKeepAlive方法(并使用EventBus全局监听)

    解释:this.$bus就是在main.js 加上:Vue.prototype.$bus = new Vue()

    <template>
      <div id="app">
        <keep-alive>
          <router-view class="Router" v-if="$route.meta.keepAlive" :key="fullPath">router-view>
        keep-alive>
        <router-view class="Router" v-if="!$route.meta.keepAlive">router-view>
      div>
    template>
    
    <script>
    export default {
      name: 'app',
      computed: {
        fullPath() {
          // console.log(this.$route.fullPath);
          return this.$route.fullPath;
        },
      },
      mounted() {
        console.log('app---mounted')
          // 注册监听全局的clearKeepAlive方法,可在其他组件中触发此方法
          this.$bus.$on("clearKeepAlive", this.clearKeepAlive);
      },
      methods: {
        // 根据fullUrl清除keepAlive
        clearKeepAlive(fullUrl) {
          // console.log('bus触发要清除的keepAlive', fullUrl);
          this.$children.forEach((item) => {
            if (item.$vnode.data.key == fullUrl) {
              // console.log('destorykeepAlive', item.$vnode.data.key, fullUrl, item);
              this.destorykeepAlive(item);
            }
          });
        },
        // 封装清除某个组件的keepAlive状态,并销毁
        destorykeepAlive(keepAliveDom) {
          if (keepAliveDom?.$vnode?.data?.keepAlive) {
            if (keepAliveDom?.$vnode?.parent?.componentInstance?.cache) {
              if (keepAliveDom.$vnode.componentOptions) {
                var key =
                  keepAliveDom.$vnode.key == null
                    ? keepAliveDom.$vnode.componentOptions.Ctor.cid +
                    (keepAliveDom.$vnode.componentOptions.tag
                      ? `::${keepAliveDom.$vnode.componentOptions.tag}`
                      : "")
                    : keepAliveDom.$vnode.key;
                var cache =
                  keepAliveDom.$vnode.parent.componentInstance.cache;
                var keys = keepAliveDom.$vnode.parent.componentInstance.keys;
                if (cache[key]) {
                  if (keys.length) {
                    var index = keys.indexOf(key);
                    if (index > -1) {
                      keys.splice(index, 1);
                    }
                  }
                  delete cache[key];
                }
              }
            }
          }
          keepAliveDom.$destroy();
        }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    2、单个列表页面使用

      beforeRouteLeave(to, from, next) {
        if (to.name !== '列表进入的详情页面name') {
         // 离开列表页面的时候:当不是进入列表详情页面时清除列表页面的缓存
          this.$bus.$emit("clearKeepAlive", from.path)
        }
        next()
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    相关文章

    基于ElementUi再次封装基础组件文档


    基于ant-design-vue再次封装基础组件文档


    vue3+ts基于Element-plus再次封装基础组件文档

  • 相关阅读:
    Excel - DAO versus ADO in VBA + RDO介绍
    干货丨数据仓库工具hive面试题集锦
    关于AtomSeg程序移植问题(持续更新)
    硫化铅量子点,PbS QDs,近红外PbS量子点的特性(波尔半径大,量子效应显著)
    【C语言】自定义类型:联合体和枚举
    什么年代了,还在用FastQC?试试Falco吧
    操作系统06-运行机制
    Vue3新的状态管理库-Pinia(保姆级别教程)
    revit中如何实现【管线编辑】?
    【C++ 科学计算】矩阵行列式计算方法
  • 原文地址:https://blog.csdn.net/cwin8951/article/details/137590859