第三十六节: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

相关推荐
ZhengEnCi8 小时前
小白用 AI 做官网完全指南:不用框架的六格清单,双击就能打开
前端·html·ai编程
zhanlang02179 小时前
HTML 零基础入门到企业实战【第五章 5.2】图片路径精讲:绝对路径、相对路径、网络路径(新手必踩坑点)
前端·html
夕水9 小时前
我用trae重构了ew-color-picker,一个插件化架构的现代颜色选择器
前端·javascript·开源
Penge6669 小时前
React JSX 核心语法:从入门到业务开发实战
前端
zhanlang02179 小时前
HTML 零基础入门到企业实战全套教程【第五章 5.5 综合案例:图文影音展示页面开发】
前端·html
tryCbest10 小时前
Vue3——第 17 篇:模板引用(ref)与组件实例——操作 DOM 的正确姿势
vue.js·前端搭建
黄连木笛10 小时前
Redis Insight 汉化教程:Windows / macOS / Linux 设置中文界面(附繁體、教程汉化、关闭自动更新)
数据库·redis·缓存
zhanlang021710 小时前
HTML 零基础入门到企业实战全套教程【连载 5.3】audio、video 音频视频标签|兼容格式、自动播放踩坑、企业规范
前端·html
qq_4069810311 小时前
c++ lamda(三)Lambda表达式
java·前端·c++
头发还在的女程序员11 小时前
Java在线租房系统源码解析:Spring Boot+Vue 3+UniApp房源管理与预约看房方案
java·vue.js·spring boot·租房小程序·租房系统·租房软件