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

5.7 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
KeepAlive Router Navigation Fresh vs Cached Problem MEDIUM When using KeepAlive with Vue Router, users may get cached pages when they expect fresh content gotcha
vue3
keepalive
vue-router
navigation
cache
ux

KeepAlive Router Navigation Fresh vs Cached Problem

Impact: MEDIUM - When using KeepAlive with Vue Router, navigation from menus or breadcrumbs may show cached (stale) content when users expect a fresh page. This creates confusing UX where the page appears "stuck" on old data.

Task Checklist

  • Define clear rules for when to use cached vs fresh pages
  • Use route keys strategically to control freshness
  • Implement onActivated to refresh stale data
  • Consider navigation source when deciding cache behavior

The Problem

<!-- App.vue -->
<template>
  <nav>
    <router-link to="/products">Products</router-link>
  </nav>

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

Scenario:

  1. User visits /products?category=shoes - sees shoes
  2. User navigates to /products?category=hats - sees hats
  3. User clicks "Products" nav link (to /products)
  4. Expected: Fresh products page or default category
  5. Actual: Still shows hats (cached state)!

Users clicking navigation expect a "fresh start" but get the cached state.

Solutions

Solution 1: Use Route Full Path as Key

<template>
  <router-view v-slot="{ Component, route }">
    <KeepAlive>
      <!-- Different query params = different cache entry -->
      <component :is="Component" :key="route.fullPath" />
    </KeepAlive>
  </router-view>
</template>

Tradeoff: Creates separate cache entry for each unique URL. May increase memory usage.

Solution 2: Refresh Data on Activation

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

const route = useRoute()
const products = ref([])
const lastParams = ref(null)

async function fetchProducts() {
  const params = route.query
  products.value = await api.getProducts(params)
  lastParams.value = JSON.stringify(params)
}

// Initial fetch
fetchProducts()

// Refresh when re-activated if params changed
onActivated(() => {
  const currentParams = JSON.stringify(route.query)
  if (currentParams !== lastParams.value) {
    fetchProducts()
  }
})

// Also watch for changes while component is active
watch(() => route.query, fetchProducts, { deep: true })
</script>

Solution 3: Navigation-Aware Cache Control

Different behavior based on how user navigated:

<script setup>
import { ref, onActivated } from 'vue'
import { useRoute, useRouter, onBeforeRouteUpdate } from 'vue-router'

const route = useRoute()
const router = useRouter()
const shouldRefresh = ref(false)

// Mark for refresh when coming from nav link (no query params)
onBeforeRouteUpdate((to, from) => {
  // If navigating to base path without params, user wants fresh view
  if (Object.keys(to.query).length === 0 && Object.keys(from.query).length > 0) {
    shouldRefresh.value = true
  }
})

onActivated(() => {
  if (shouldRefresh.value) {
    resetToDefaultState()
    shouldRefresh.value = false
  }
})

function resetToDefaultState() {
  // Reset filters, clear search, show default view
}
</script>

Solution 4: Don't Cache Route-Dependent Pages

<script setup>
// Don't cache pages where query params significantly change content
const noCacheRoutes = ['ProductSearch', 'SearchResults', 'FilteredList']
</script>

<template>
  <router-view v-slot="{ Component, route }">
    <KeepAlive :exclude="noCacheRoutes">
      <component :is="Component" />
    </KeepAlive>
  </router-view>
</template>

Solution 5: Use Route Meta for Fresh Navigation

// router.js
const routes = [
  {
    path: '/products',
    component: Products,
    meta: {
      keepAlive: true,
      refreshOnDirectNavigation: true
    }
  }
]
<!-- App.vue -->
<script setup>
import { watch } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()
const forceRefreshKey = ref(0)

// Watch for navigation to routes that want fresh state
watch(
  () => route.fullPath,
  (newPath, oldPath) => {
    // Direct navigation to base path = user wants fresh
    if (route.meta.refreshOnDirectNavigation && !route.query.length) {
      forceRefreshKey.value++
    }
  }
)
</script>

<template>
  <router-view v-slot="{ Component }">
    <KeepAlive>
      <component
        :is="Component"
        :key="`${route.name}-${forceRefreshKey}`"
      />
    </KeepAlive>
  </router-view>
</template>

Best Practice: Be Explicit About Cache Behavior

Document your caching rules:

// cacheRules.js
export const CACHE_RULES = {
  // Always cached - static content, user preferences
  ALWAYS: ['Dashboard', 'Settings', 'Profile'],

  // Never cached - dynamic search/filter results
  NEVER: ['SearchResults', 'FilteredProducts'],

  // Cached but refreshes on activation
  STALE_WHILE_REVALIDATE: ['Notifications', 'Messages']
}

Key Points

  1. User expectation mismatch - Nav links often imply "fresh" but get cached
  2. Use fullPath key carefully - Prevents reuse but increases memory
  3. Implement onActivated refresh - Check if data needs updating
  4. Don't cache filter/search pages - These are highly query-dependent
  5. Document cache behavior - Make rules explicit for your team

Reference