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文件修改

html 复制代码
<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>

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

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

js 复制代码
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)
  },

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

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

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

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

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

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

html 复制代码
<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>

2、单个列表页面使用

js 复制代码
  beforeRouteLeave(to, from, next) {
    if (to.name !== '列表进入的详情页面name') {
     // 离开列表页面的时候:当不是进入列表详情页面时清除列表页面的缓存
      this.$bus.$emit("clearKeepAlive", from.path)
    }
    next()
  },

相关文章

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


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


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

相关推荐
FRing0313 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
徐小夕16 小时前
深度剖析 30k star 的编码 Agent DeepSeek-Reasonix:长会话 Token 成本直降 80%
前端·vue.js·github
ruanno_top18 小时前
1 万行表格只渲染 18 行:虚拟滚动让我放弃了三个功能
vue.js
仨孩子的爹19 小时前
套打总偏两毫米:预印刷单据的校准方法和三个误区
vue.js
徐小夕19 小时前
JitKnow知识库4.8发布:本体+知识图谱检索引擎,让AI回答不再“一本正经地胡说八道”
前端·vue.js·github
tryCbest19 小时前
Vue3——第 11 篇:组合式 API(上)——setup 与响应式 API 深度解析
前端·javascript·vue.js
tryCbest20 小时前
Vue3——第 13 篇:计算属性与侦听器——computed 与 watch 的进化
前端·javascript·vue.js
闲来没事抠鼻屎21 小时前
标签打印 8 个尺寸公式:小票、价签、吊牌、面单通用
vue.js
时间的情敌21 小时前
Vue3 + Cesium 实战:本地上传 GLB 模型、模型上叠加 GLB、点击控制透明度
前端·vue.js·cesium
小蒜学长1 天前
基于SpringBoot+Vue的云南地区扶贫助农系统的设计与实现(代码+数据库+LW)
java·vue.js·spring boot·后端·乡村振兴