移动端使用keep-alive将页面缓存和滚动缓存具体实现方法 - 详解

1. 配置组件名称

确保列表页组件设置了name选项,(组合式API额外配置):

TypeScript 复制代码
<!-- vue2写法 --> 
export default {
  name: 'UserList' // 必须与 <keep-alive> 的 include 匹配
}

<!-- vue3写法 --> 
defineOptions({
  name: "UserList"
});

2. 路由配置

在路由配置中添加 meta 标识是否需要缓存:

TypeScript 复制代码
{
    path: "/userList",
    name: "UserList",
    component: () => import("@/views/user/list.vue"),
    meta: {
      title: "用户列表",
      keepAlive: true // 自定义缓存标识
    }
  },

3. 动态缓存控制

在 App.vue 中使用 <keep-alive> 包裹路由视图,并动态判断缓存:

TypeScript 复制代码
<!-- App.vue -->
<template>
  <router-view v-slot="{ Component, route }">
    <keep-alive :include="cachedViews">
      <component
        :is="Component"
        :key="route.fullPath"
        v-if="route.meta.keepAlive"
      />
    </keep-alive>
    <component
      :is="Component"
      :key="route.fullPath"
      v-if="!route.meta.keepAlive"
    />
  </router-view>
</template>

<script setup lang="ts">
import { ref, watch } from "vue";
import { useRoute } from "vue-router";

const cachedViews = ref([]);
const route = useRoute();

watch(
  () => route.meta.keepAlive,
  newVal => {
    if (newVal && !cachedViews.value.includes(route.name)) {
      cachedViews.value.push(route.name);
    }
  }
);
</script>

4. 生命周期钩子

在列表页组件中使用 activated 钩子(vue3 使用 onActivated ) 处理返回时的逻辑:

TypeScript 复制代码
<div class="list_box" @scroll="handleScroll" ref="listRef"> 
    <van-list
        v-model:loading="loading"
        :finished="finished"
        finished-text="没有更多了"
        @load="getList"
    >
    .......
    </van-list>
</div>

const listRef = ref(null);
// 缓存分页和滚动位置
const cachedState = ref({
  page: 1,
  scrollTop: 0
});

// 滚动事件处理
const handleScroll = e => {
  // 实时保存滚动位置
  cachedState.value.scrollTop = e.target.scrollTop;
  // console.log("cachedState.value.scrollTop", cachedState.value.scrollTop);
};

onActivated(async () => {
  console.log("组件激活,执行激活时的操作", cachedState.value.page);
  if (cachedState.value.page > 1) {
    searchQuery.page = cachedState.value.page;
  }
  await nextTick();
  // 恢复滚动位置
  if (listRef.value) {
    listRef.value.scrollTop = cachedState.value.scrollTop;
  }
});

onDeactivated(() => {
  // 保存当前状态
  cachedState.value.page = searchQuery.page;
  console.log("组件停用", cachedState.value.page);
});

6. 高级场景:条件缓存

TypeScript 复制代码
// 在全局前置守卫中
router.beforeEach((to, from) => {
  if (from.name?.toString().includes('Detail') && to.name === 'UserList') {
    to.meta.keepAlive = true // 从详情页返回时缓存
  } else if (to.name === 'ListPage') {
    to.meta.keepAlive = false // 从其他页面进入时不缓存
  }
})
相关推荐
闲猫2 分钟前
Python FastAPI + SQLAlchemy 入门教程:从零搭建你的第一个 Web 应用
前端·python·fastapi
林小帅26 分钟前
NestJS v11 + Prisma v7 ESM 迁移配置解析
前端·javascript·后端
IT_陈寒42 分钟前
React的setState竟然不是立刻生效的,害我调试半天
前端·人工智能·后端
简简单单就是我_hehe1 小时前
前端埋点日志解决方案:完整 User-Agent 解析工具实现,爬虫识别、设备品牌、操作系统、浏览器版本全解析(附完整源码)
前端·爬虫
William_Xu2 小时前
Vue 2 与 Vue 3 生命周期对比
前端
Hilaku2 小时前
为什么你的大文件断点续传,一遇到弱网就崩溃?
前端·javascript·程序员
烟漠河洛2 小时前
线上事故复盘:Redis幂等性设计边界没覆盖跨状态请求,订单状态机直接崩了
数据库·redis·缓存
胡哈3 小时前
React Compiler:让开发者忘掉 memo 这件事
前端·react.js
xiyueyezibile3 小时前
“自迭代” Skill 的 team-pitfalls 的演进
前端·后端·ai编程
林恒smileZAZ3 小时前
`Array(100).map(() => 1)` 为什么全为空?
前端·javascript