第三十六节:keep-alive 页面缓存(Vue3 + 后台管理系统)

第三十六节:keep-alive 页面缓存(Vue3 + 后台管理系统)

本节目标:

实现路由页面缓存 ,切换标签页回来保留表单 / 表格查询条件、页码;离开页面不销毁组件;不需要缓存的页面可以排除。

对应咱们项目的 TagsView 标签页,就是搭配 keep-alive 使用,属于当前主线内容,现在直接讲。

原理

keep-alive 是 Vue 内置组件,缓存组件实例,不会销毁

  • 打开页面:onMounted 只执行一次
  • 切走再切回来:不会重新请求接口,直接复用之前 DOM 和数据
  • 生命周期:onActivated(激活,每次进入) / onDeactivated(失活,切走)

步骤 1:修改布局 src/layout/index.vue

复制代码
<template>
  <div class="layout-container">
    <Sidebar />
    <div class="main-container">
      <AppHeader />
      <TagsView />
      <!-- 核心:keep-alive + router-view -->
      <router-view v-slot="{ Component }">
        <keep-alive :include="cachedViews">
          <component :is="Component" />
        </keep-alive>
      </router-view>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useTagsViewStore } from '@/stores/tagsView'
const tagsViewStore = useTagsViewStore()
// 从pinia取出需要缓存的页面名称数组
const cachedViews = ref(tagsViewStore.cachedViews)
</script>

步骤 2:改造 src/stores/tagsView.js

新增 cachedViews 数组,用来存放组件 name ,keep-alive 的 include 靠组件 name 匹配缓存!

⚠️重点坑:keep-alive 匹配的是组件选项 name,不是路由 path!

复制代码
import { defineStore } from 'pinia'
export const useTagsViewStore = defineStore('tagsView', {
  state: () => ({
    visitedViews: [], // 标签页列表(展示用)
    cachedViews: []   // keep-alive缓存名称数组
  }),
  actions: {
    // 添加标签,同时加入缓存
    addView(view) {
      if (this.visitedViews.some(v => v.path === view.path)) return
      this.visitedViews.push({
        path: view.path,
        title: view.meta?.title || 'no-name'
      })
      // 有组件name,才加入缓存
      if (view.name && !this.cachedViews.includes(view.name)) {
        this.cachedViews.push(view.name)
      }
    },
    // 删除标签,同时移除缓存
    delView(view) {
      const index = this.visitedViews.findIndex(v => v.path === view.path)
      if (index > -1) {
        this.visitedViews.splice(index, 1)
      }
      // 删除缓存名称
      if (view.name) {
        const cacheIndex = this.cachedViews.indexOf(view.name)
        if (cacheIndex > -1) {
          this.cachedViews.splice(cacheIndex, 1)
        }
      }
      // 返回剩下的标签用于页面跳转
      return this.visitedViews[this.visitedViews.length - 1]
    },
    // 关闭其他标签
    delOthersViews(view) {
      this.visitedViews = this.visitedViews.filter(item => {
        return item.path === view.path || item.path === '/dashboard/index'
      })
      this.cachedViews = this.cachedViews.filter(name => {
        return view.name === name || name === 'Dashboard'
      })
    },
    // 关闭全部
    delAllViews() {
      const dashboard = this.visitedViews.find(v => v.path === '/dashboard/index')
      this.visitedViews = dashboard ? [dashboard] : []
      this.cachedViews = dashboard ? ['Dashboard'] : []
    }
  }
})

步骤 3:给业务页面添加 name 属性(必须!)

示例 src/views/system/user/index.vue

复制代码
<script setup>
// ✅ 定义组件name,keep-alive靠这个识别
defineOptions({
  name: 'UserList'
})
// 剩下你的页面逻辑...
</script>

工作台页面 dashboard/index.vue

复制代码
<script setup>
defineOptions({
  name: 'Dashboard'
})
</script>

步骤 4:生命周期变化(缓存页面要用)

复制代码
// 首次进入执行一次
onMounted(() => {
  console.log('组件挂载')
})
// ✅ 每次切换标签回来都会执行(缓存页面推荐在这里请求数据)
onActivated(() => {
  console.log('页面激活')
  // getList()
})
// ✅ 页面切走失活
onDeactivated(() => {
  console.log('页面缓存,暂时隐藏')
})

测试清单

  1. 重启项目,进入用户管理页面,设置查询条件、页码
  2. 切到别的标签,再切回用户管理
    ✅ 查询条件、页码保留,不会重新刷新页面
  3. 关闭标签,cachedViews 自动移除组件 name,再次打开页面会重新加载
  4. 关闭其他标签、关闭全部,缓存数组同步清理

常见坑

  1. ❗忘记写 defineOptions({name:'xxx'}) → keep-alive 不生效

  2. 动态路由路由对象里要把路由的 name 带上,mock 路由补充 name 字段

    {
    path: '/system',
    component: 'Layout',
    name: 'System',
    meta: { title: '系统管理', icon: 'Setting' },
    children: [
    {
    path: 'user/list',
    component: 'system/user/index',
    name: 'UserList',
    meta: { title: '用户列表', icon: 'User' }
    }
    ]
    }

  3. 如果不需要缓存某个页面:不写组件 name 即可,不会进入 cachedViews

相关推荐
言乐61 小时前
Python加速器2视频网页加速器
前端·javascript·css·python·音视频
我是苏苏1 小时前
Redis开发09:Windows系统下主从复制的配置教程
数据库·redis·缓存
边境悍匪1 小时前
蜗牛学苑 Java 智能体学习 Day41|ElementPlus 布局、Vue‑Router 登录、Axios 思维导图复盘
java·vue.js·学习
IT_陈寒1 小时前
为什么我的Java Stream操作总是默默吃掉异常?
前端·人工智能·后端
志尊宝1 小时前
Vue3 零基础每日笔记(017):事件处理进阶——$event、多事件与事件修饰符全家桶
javascript·vue.js·笔记
光影少年2 小时前
react navite浏览器 Event Loop 和 Node Event Loop 的区别
前端·javascript·react native·react.js·前端框架
90后的晨仔2 小时前
uni-app 安卓自有证书完全指南
前端
mengzhi啊12 小时前
缓存类CacheDataManager把临时数据存入json。做成插件·
qt·缓存·json