微信小程序 wx:for 列表渲染:wx:key 与 block 实测
微信小程序 wx:for 用来把页面 data 中的数组展开成一组 WXML 节点。语法本身不难,真正容易出错的是三个细节:循环数据写在哪、什么时候需要 <block>,以及 wx:key 应该填字段名还是 *this。
这篇不另造一个只为截图存在的示例。我直接使用此前在微信开发者工具和 iPhone 真机中运行过的原生分包项目,抽取首页的“当前代码包”列表,并用脚本重新核对 WXML、页面 data 和最终三项输出之间是否一致。
先看这次真实项目里的列表
首页需要显示主包、普通分包和独立分包三个标签。数据放在 pages/home/index.js 的 data 中:
Page({
data: {
packageSummary: [
'主包:home、profile',
'普通分包:packages/order',
'独立分包:packages/campaign'
]
}
})
WXML 不需要手写三个重复的 view。循环写在一个虚拟 block 上,数组中的每个字符串通过 {{item}} 输出:
<block wx:for="{{packageSummary}}" wx:key="*this">
<view class="tag">{{item}}</view>
</block>
本轮静态检查实际读取了这两个文件,并捕获页面定义中的数组。六项断言全部通过:数据确实是数组、循环指向 packageSummary、使用虚拟 block、存在 item 绑定、字符串列表使用 *this,而且三项 key 均不重复。
| index | item / key | 渲染结果 |
|---|---|---|
| 0 | 主包:home、profile | 一个标签节点 |
| 1 | 普通分包:packages/order | 一个标签节点 |
| 2 | 独立分包:packages/campaign | 一个标签节点 |
也就是说,一份三项数组最终生成三个同结构节点;WXML 负责描述重复结构,具体内容仍以页面 data 为事实来源。
wx:for 默认提供 item 和 index
wx:for 展开数组时,会在循环内部提供两个临时变量:
item:当前这一项的值。index:当前项在数组中的下标,从 0 开始。
<view wx:for="{{packageSummary}}" wx:key="*this">
第 {{index}} 项:{{item}}
</view>
如果内层结构也有循环,继续使用默认名字很容易把外层 item 遮住。可以显式改名:
<view
wx:for="{{packageSummary}}"
wx:for-item="packageItem"
wx:for-index="packageIndex"
wx:key="*this"
>
{{packageIndex}}:{{packageItem}}
</view>
改名不会改变原数组,只是让当前模板里的临时变量更明确。嵌套列表、表格行或卡片内再循环标签时,这个习惯比到处猜 item 属于哪一层更可靠。
什么时候把 wx:for 写在 block 上
如果每次循环只生成一个根节点,把 wx:for 直接写在这个节点上即可。只有一次循环要生成多个同级节点时,才需要用 <block> 包起来:
<block wx:for="{{orders}}" wx:key="id">
<view class="order-title">{{item.title}}</view>
<view class="order-price">{{item.price}}</view>
</block>
block 是 WXML 的虚拟包装,不会像普通 view 那样额外生成一个可见容器。它适合组织模板逻辑,但不能把它当成真实布局元素去设置 class、间距或背景;需要参与布局时,仍应使用 view。
wx:key:字段名和 *this 怎么选
wx:key 用于在列表变化时标识每一项。最常见的两种写法对应两类数据。
对象数组:直接写稳定字段名
Page({
data: {
orders: [
{ id: 'A1001', title: '订单一' },
{ id: 'A1002', title: '订单二' }
]
}
})
<view wx:for="{{orders}}" wx:key="id">
{{item.title}}
</view>
这里写的是 wx:key="id",不是 wx:key="{{item.id}}"。key 值来自当前对象的 id 字段;这个字段应尽量唯一,而且不要因为排序或文案变化而改变。
字符串或数字数组:可使用 *this
本次项目中的 packageSummary 是字符串数组,没有 id 字段,因此使用 wx:key="*this",让当前字符串本身作为 key。前提是各项不重复;如果数组里出现两个完全相同的字符串,它们就不能提供足够稳定的区分。
不要把“所有列表都必须加 key”当成定律
微信当前官方文档特别说明:使用 wx:key 不一定提升列表渲染性能,有时反而可能带来负面影响。固定不变的列表、只在末尾增加或删除项目的列表,或者找不到有代表性字段的列表,不应为了消除心理负担而随便拿 index、标题或会变化的值充当 key。
更实用的判断是:列表是否会重排或在中间插入、删除?每项是否有稳定且唯一的业务标识?两项都成立时再选 key,通常比机械复制旧教程更稳妥。
四个常见错误怎么查
| 现象 | 优先检查 | 处理方式 |
|---|---|---|
| 页面一个节点都没有 | wx:for 指向的字段名 | 确认字段确实位于当前页面或组件的 data,并且值是数组 |
| 文字显示为空 | 循环变量名称 | 确认使用默认 item,或与 wx:for-item 的自定义名称一致 |
| 出现 key 警告或更新错位 | key 是否重复、是否会变化 | 对象使用稳定唯一字段;原始值数组只有在值唯一时使用 *this |
| 样式包不住多节点 | 是否把 block 当成真实容器 | 需要布局和样式时改用 view,不要给虚拟 block 承担布局 |
如果文件路径、页面注册或全局配置本身有问题,先对照微信小程序项目目录结构和app.json 与页面 JSON 的作用域排除基础问题。列表恰好位于分包页面时,再检查subPackages 的 root 与页面路径,不要把“页面没注册”误判成 wx:for 失效。
列表项同时包含整行点击和行内按钮时,还要留意 tap 事件继续向父级传播;可结合微信小程序 bindtap 与 catchtap 的事件冒泡实作一起排查重复触发。
如何复现本次检查
项目根目录下执行本次检查脚本:
node codex-wechat-mini-program/verify-wxml-list-rendering.mjs
脚本会读取真实的 pages/home/index.wxml 与 pages/home/index.js,捕获页面 data,检查循环目标、虚拟 block、*this、item 绑定和 key 唯一性。本轮结果为 6 项全部通过,输出三条与数组顺序一致的标签数据。
官方资料:微信开放文档《数据绑定》、微信开放文档《列表渲染》(访问日期:2026-08-29;本次项目此前实测工具为微信开发者工具 Stable 2.02.2608060、基础库 3.17.1,本轮结论重新以当前官方 WXML 文档和项目静态断言核对)。




