fix(小程序): 修正 v-for :key 表达式告警,恢复列表 wx:key
非 h5 平台的 :key 只接受简单属性名,模板字面量与运算表达式会被编译器
整条丢弃(uni-template-compiler 的 getForKey:Identifier 走 *this 或原名,
MemberExpression 取属性名,其余一律 warning + 返回空串)。
所以这批告警不只是文案问题:产物里对应的 <block wx:for> 后面确实没有
wx:key,列表项因此失去复用标识,增删时会整段重建节点。本次按编译器
接受的写法逐一改正,共 13 个文件。
改法:
- 纯 URL 字符串数组(打卡/门头/小票/凭证/巡店照片)直接用元素自身
:key="img",编译为 wx:key="*this"
- 对象数组用其已有唯一字段:连锁/门店 item.id、抄送用户 user.id、
审计销量行 detail.key、编辑销量项 detail._key
- 本身无唯一字段的巡店列表补 _key:task/detail 沿用 visit.vue 已验证的
_rowKey(自增 seed,增删稳定),records 与 AuditVisitReportItem 用序号
sales.vue 另有一处隐蔽问题:row 是 {item, index} 包装对象,
:key="row.item._key || row.index" 即便写成简单形式也会生成 wx:key="_key",
在 row 上取不到值。改为在 visibleSalesItems 里把 key 提到包装对象顶层,
_key 缺失时用序号兜底。create.vue 的销量摘要同样补 __key 兜底,避免重复 key。
注:task/detail 的 storeList 提交走 sanitizeStoreList() 显式白名单,
_rowKey 不会外泄到后端。
验证:HBuilderX cli 重新编译 —— 编译成功,非 h5 平台 :key 告警 0 条
(修改前满屏 40+ 条),产物中 wx:for 与 wx:key 数量逐文件相等。
This commit is contained in:
@@ -59,7 +59,7 @@
|
||||
<view class="section-extra">最多{{ boothLimit }}张</view>
|
||||
</view>
|
||||
<view class="photo-grid">
|
||||
<view v-for="(item, idx) in boothPhotos" :key="`booth-${idx}`" class="photo-item">
|
||||
<view v-for="(item, idx) in boothPhotos" :key="item" class="photo-item">
|
||||
<image :src="item" mode="aspectFill" class="photo-image" @tap="previewImages(boothPhotos, item)"/>
|
||||
<view class="photo-remove" @tap="removeBooth(idx)">x</view>
|
||||
</view>
|
||||
@@ -95,7 +95,7 @@
|
||||
</view>
|
||||
<view v-if="salesItems.length === 0" class="audit-empty-tip">请点击上方进入「销量填写」添加商品</view>
|
||||
<view v-else class="sales-summary-list">
|
||||
<view class="sales-summary-item" v-for="(item, idx) in salesSummaryRows" :key="item._key || idx">
|
||||
<view class="sales-summary-item" v-for="(item, idx) in salesSummaryRows" :key="item._key">
|
||||
<text class="sales-summary-name">{{ item.name }}</text>
|
||||
<text class="sales-summary-qty">{{ formatSalesQty(item.qty) }}{{ item.unit || '盒' }}</text>
|
||||
</view>
|
||||
@@ -119,7 +119,7 @@
|
||||
<view class="section-extra">最多{{ receiptLimit }}张</view>
|
||||
</view>
|
||||
<view class="photo-grid">
|
||||
<view v-for="(item, idx) in receiptPhotos" :key="`receipt-${idx}`" class="photo-item">
|
||||
<view v-for="(item, idx) in receiptPhotos" :key="item" class="photo-item">
|
||||
<image :src="item" mode="aspectFill" class="photo-image" @tap="previewImages(receiptPhotos, item)"/>
|
||||
<view class="photo-remove" @tap="removeReceipt(idx)">x</view>
|
||||
</view>
|
||||
@@ -201,7 +201,7 @@
|
||||
@change="onChainPickerChange"
|
||||
>
|
||||
<picker-view-column>
|
||||
<view v-for="(item, idx) in merchantChainOptions" :key="`chain-${idx}`" class="merchant-picker-item">
|
||||
<view v-for="(item, idx) in merchantChainOptions" :key="item.id" class="merchant-picker-item">
|
||||
{{ item.text }}
|
||||
</view>
|
||||
</picker-view-column>
|
||||
@@ -232,7 +232,7 @@
|
||||
@change="onMerchantPickerChange"
|
||||
>
|
||||
<picker-view-column>
|
||||
<view v-for="(item, idx) in merchantStoreOptions" :key="`merchant-${idx}`" class="merchant-picker-item">
|
||||
<view v-for="(item, idx) in merchantStoreOptions" :key="item.id" class="merchant-picker-item">
|
||||
{{ item.text }}
|
||||
</view>
|
||||
</picker-view-column>
|
||||
@@ -360,7 +360,11 @@ export default {
|
||||
},
|
||||
salesSummaryRows() {
|
||||
const items = Array.isArray(this.salesItems) ? this.salesItems : []
|
||||
return items.slice(0, this.salesSummaryLimit)
|
||||
// wx:key 需要稳定唯一标识;销量项正常都带 _key(销量页生成/重提回填),
|
||||
// 旧草稿缺失时按序号兜底,避免出现重复 key
|
||||
return items.slice(0, this.salesSummaryLimit).map((item, index) => Object.assign({}, item, {
|
||||
_key: (item && item._key) ? item._key : `sales_summary_${index}`
|
||||
}))
|
||||
},
|
||||
totalRewardAmount() {
|
||||
return (Array.isArray(this.salesItems) ? this.salesItems : []).reduce((sum, item) => {
|
||||
|
||||
Reference in New Issue
Block a user