- 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: 下拉刷新 / 上拉加载 - 产品首页: 添加业务联系 - 文档: 清理过时文件,补充缺失规范章节
5.0 KiB
5.0 KiB
title, impact, impactDescription, type, tags
| title | impact | impactDescription | type | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Use v-once and v-memo to Skip Unnecessary Updates | MEDIUM | v-once skips all future updates for static content; v-memo conditionally memoizes subtrees | efficiency |
|
Use v-once and v-memo to Skip Unnecessary Updates
Impact: MEDIUM - Vue re-evaluates templates on every reactive change. For content that never changes or changes infrequently, v-once and v-memo tell Vue to skip updates, reducing render work.
Use v-once for truly static content and v-memo for conditionally-static content in lists.
Task Checklist
- Apply
v-onceto elements that use runtime data but never need updating - Apply
v-memoto list items that should only update on specific condition changes - Verify memoized content doesn't need to respond to other state changes
- Profile with Vue DevTools to confirm update skipping
v-once: Render Once, Never Update
Incorrect:
<template>
<!-- BAD: Re-evaluated on every parent re-render -->
<div class="terms-content">
<h1>Terms of Service</h1>
<p>Version: {{ termsVersion }}</p>
<div v-html="termsContent"></div>
</div>
<!-- This content NEVER changes, but Vue checks it every render -->
<footer>
<p>Copyright {{ copyrightYear }} {{ companyName }}</p>
</footer>
</template>
Correct:
<template>
<!-- GOOD: Rendered once, skipped on all future updates -->
<div class="terms-content" v-once>
<h1>Terms of Service</h1>
<p>Version: {{ termsVersion }}</p>
<div v-html="termsContent"></div>
</div>
<!-- v-once tells Vue this never needs to update -->
<footer v-once>
<p>Copyright {{ copyrightYear }} {{ companyName }}</p>
</footer>
</template>
<script setup>
// These values are set once at component creation
const termsVersion = '2.1'
const termsContent = fetchedTermsHTML
const copyrightYear = 2024
const companyName = 'Acme Corp'
</script>
v-memo: Conditional Memoization for Lists
Incorrect:
<template>
<!-- BAD: All items re-render when selectedId changes -->
<div v-for="item in list" :key="item.id">
<div :class="{ selected: item.id === selectedId }">
<ExpensiveComponent :data="item" />
</div>
</div>
</template>
Correct:
<template>
<!-- GOOD: Items only re-render when their selection state changes -->
<div
v-for="item in list"
:key="item.id"
v-memo="[item.id === selectedId]"
>
<div :class="{ selected: item.id === selectedId }">
<ExpensiveComponent :data="item" />
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const list = ref([/* many items */])
const selectedId = ref(null)
// When selectedId changes:
// - Only the previously-selected item re-renders (selected: true -> false)
// - Only the newly-selected item re-renders (selected: false -> true)
// - All other items are SKIPPED (v-memo values unchanged)
</script>
v-memo with Multiple Dependencies
<template>
<!-- Re-render only when item's selection OR editing state changes -->
<div
v-for="item in items"
:key="item.id"
v-memo="[item.id === selectedId, item.id === editingId]"
>
<ItemCard
:item="item"
:selected="item.id === selectedId"
:editing="item.id === editingId"
/>
</div>
</template>
<script setup>
const selectedId = ref(null)
const editingId = ref(null)
const items = ref([/* ... */])
</script>
v-memo with Empty Array = v-once
<template>
<!-- v-memo="[]" is equivalent to v-once -->
<div v-for="item in staticList" :key="item.id" v-memo="[]">
{{ item.name }}
</div>
</template>
When NOT to Use These Directives
<template>
<!-- DON'T: Content that DOES need to update -->
<div v-once>
<span>Count: {{ count }}</span> <!-- count won't update! -->
</div>
<!-- DON'T: When child components have their own reactive state -->
<div v-memo="[selected]">
<InputField v-model="item.name" /> <!-- v-model won't work properly -->
</div>
<!-- DON'T: When the memoization benefit is minimal -->
<span v-once>{{ simpleText }}</span> <!-- Overhead not worth it -->
</template>
Performance Comparison
| Scenario | Without Directive | With v-once/v-memo |
|---|---|---|
| Static header, parent re-renders 100x | Re-evaluated 100x | Evaluated 1x |
| 1000 items, selection changes | 1000 items re-render | 2 items re-render |
| Complex child component | Full re-render | Skipped if memoized |
Debugging Memoized Components
<script setup>
import { onUpdated } from 'vue'
// This won't fire if v-memo prevents update
onUpdated(() => {
console.log('Component updated')
})
</script>