12451 b553c4e519 feat: API 统一 + 设备详情补全 + H5 导航优化
- API 路由统一: 移除 /api/h5/,统一 /api/pms/ 入口
- 二进制改名: api-server -> pms-api(与服务名一致)
- nginx: 合并 /api/ + /pms/api/ 为 /api/pms/
- 新增 docs/API.md 接口文档
- 后端: CabinetDetail 增加 rssi/pow_fail/address/soc 等字段
- Redis 管道批量读取仓体实时数据(SOC/电压/电流/功率)
- DB: 所有 TIMESTAMP 列改为 DATETIME(修复类型不匹配)
- 用户管理: 新增创建时间/修改时间列,状态改用 Switch
- 角色管理/用户管理: 操作按钮改为图标
- PC 设备详情: 基本信息补全 RSSI/ICCID/电源/地址
- PC 卡片: 通道统计改用 Lucide 图标,颜色统一
- PC 二维码: canvas 渲染,含编号文字,支持右键下载
- H5: 按 uni-app 规范修正导航(navigateTo 替代 reLaunch)
- H5: 详情页加返回导航条
- H5: 扫码支持摄像头(jsQR)+ ?id= 参数
- H5: 底部 tabBar 在所有页面常显
- H5: 首页统计改为 6 项(设备/通道/空闲/充电/充满/故障)
- H5: 下拉刷新 / 上拉加载
- 产品首页: 添加业务联系
- 文档: 清理过时文件,补充缺失规范章节
2026-07-04 04:03:02 +08:00

4.5 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Vue 3 KeepAlive Has No Direct Cache Removal API MEDIUM Unlike Vue 2, there is no way to programmatically remove a specific component from KeepAlive cache in Vue 3 gotcha
vue3
keepalive
cache
migration
vue2-to-vue3

Vue 3 KeepAlive Has No Direct Cache Removal API

Impact: MEDIUM - Vue 3 removed the $destroy() method that Vue 2 developers used to indirectly clear KeepAlive cache entries. There is no direct API to remove a specific cached component in Vue 3.

Task Checklist

  • Do not rely on programmatic cache removal from Vue 2 patterns
  • Use include/exclude props for dynamic cache control
  • Use key changes to force cache invalidation
  • Set appropriate max prop to auto-evict old entries

The Problem

Vue 2 Pattern (No Longer Works)

// Vue 2: Could destroy specific component instance
this.$children[0].$destroy()

Vue 3: No Equivalent API

// Vue 3: $destroy() does not exist
// There is NO direct way to remove a specific cached instance

Solutions

Solution 1: Dynamic Include/Exclude

Control cache membership via reactive props:

<script setup>
import { ref, computed } from 'vue'

const cachedViews = ref(['Dashboard', 'Settings', 'Profile'])

function removeFromCache(viewName) {
  cachedViews.value = cachedViews.value.filter(v => v !== viewName)
}

function addToCache(viewName) {
  if (!cachedViews.value.includes(viewName)) {
    cachedViews.value.push(viewName)
  }
}
</script>

<template>
  <KeepAlive :include="cachedViews">
    <component :is="currentView" />
  </KeepAlive>
</template>

When a component is removed from include, it will be destroyed on next switch.

Solution 2: Key-Based Cache Invalidation

Change the key to force a fresh instance:

<script setup>
import { ref, reactive } from 'vue'

const currentView = ref('Dashboard')
const viewKeys = reactive({
  Dashboard: 0,
  Settings: 0,
  Profile: 0
})

function invalidateCache(viewName) {
  viewKeys[viewName]++
}

function switchView(viewName) {
  currentView.value = viewName
}

// Force fresh Dashboard on next visit
function refreshDashboard() {
  invalidateCache('Dashboard')
}
</script>

<template>
  <KeepAlive>
    <component
      :is="currentView"
      :key="`${currentView}-${viewKeys[currentView]}`"
    />
  </KeepAlive>
</template>

Solution 3: Conditional KeepAlive

Wrap or unwrap based on cache need:

<script setup>
import { ref } from 'vue'

const currentView = ref('Dashboard')
const shouldCache = ref(true)

function clearCacheAndSwitch(viewName) {
  shouldCache.value = false
  currentView.value = viewName
  // Re-enable caching after the switch
  nextTick(() => {
    shouldCache.value = true
  })
}
</script>

<template>
  <KeepAlive v-if="shouldCache">
    <component :is="currentView" />
  </KeepAlive>
  <component v-else :is="currentView" />
</template>

Solution 4: Use Max for Automatic Eviction

Let LRU cache handle cleanup:

<template>
  <!-- Automatically evicts least recently used when cache is full -->
  <KeepAlive :max="5">
    <component :is="currentView" />
  </KeepAlive>
</template>

Vue Router: Clear Cache on Certain Navigations

<script setup>
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()
const cachedRoutes = ref(['Dashboard', 'Settings'])

// Clear specific route from cache when navigating from certain paths
watch(() => route.name, (newRoute, oldRoute) => {
  if (oldRoute === 'Login') {
    // User just logged in - clear and refresh Dashboard
    cachedRoutes.value = cachedRoutes.value.filter(r => r !== 'Dashboard')
    nextTick(() => {
      cachedRoutes.value.push('Dashboard')
    })
  }
})
</script>

<template>
  <router-view v-slot="{ Component }">
    <KeepAlive :include="cachedRoutes">
      <component :is="Component" />
    </KeepAlive>
  </router-view>
</template>

Key Points

  1. No $destroy() in Vue 3 - Cannot directly remove cached instances
  2. Use dynamic include - Reactively control which components are cached
  3. Use key changes - Changing key creates a new cache entry
  4. Use max prop - LRU eviction handles cleanup automatically
  5. Plan cache strategy - Design around these constraints upfront

Reference