动态的魔法:列表与条件渲染
动态的魔法:列表与条件渲染
所属专栏:《微信小程序-实战笔记30讲》
作者:码力无边
前言
到目前为止,我们构建的页面大多是“写死的”。一个按钮,一段文字,一张图片,它们都在WXML代码中清晰可见。但真实的应用世界远非如此。新闻列表的文章数量是不固定的,商品列表的商品种类是动态变化的,用户的个人中心会根据是否登录显示不同的内容。
如何让我们的页面根据数据的变化,动态地“生长”出不同的结构?
今天,我们将学习小程序中实现这一目标的两大“魔法”:
wx:for
列表渲染:像施展“分身术”一样,根据一个数组,批量生成重复的页面结构。wx:if
/wx:else
条件渲染:如同拥有“变身”能力,根据一个条件,决定某块内容是否应该出现在页面上。
掌握了这两个指令,你的WXML将不再是僵硬的模板,而是能够响应数据、富有生命力的动态画布。
一、wx:for
:列表渲染的“分身术”
wx:for
是小程序中用于循环渲染一个组件的指令。它能接收一个数组,并对数组中的每个成员,都渲染一次该组件。
1. 基础用法
wx:for
的基本语法非常直观:
<view wx:for="{{array}}">第 {{index}} 个元素:{{item}}
</view>
wx:for="{{array}}"
:array
是你在页面.js
文件的data
中定义的一个数组。item
:在循环过程中,item
是当前数组元素的值的默认变量名。index
:在循环过程中,index
是当前数组元素的下标的默认变量名。
动手实践 - 渲染一个简单的水果列表:
JS (准备数据):
// pages/list/list.js
Page({data: {fruits: ['苹果', '香蕉', '橙子', '葡萄']}
})
WXML (循环渲染):
<!-- pages/list/list.wxml -->
<view class="title">我喜欢的水果:</view>
<view wx:for="{{fruits}}" class="fruit-item">{{index + 1}}. {{item}}
</view>
保存后,模拟器上会清晰地渲染出四行水果名称。如果你去修改.js
中fruits
数组的内容(增加或删除),页面也会自动更新,这就是数据驱动的魅力。
2. 自定义变量名
如果你觉得item
和index
这两个名字不够清晰,或者在嵌套循环中容易混淆,可以使用wx:for-item
和wx:for-index
来指定新的变量名。
<view wx:for="{{fruits}}" wx:for-item="fruit" wx:for-index="idx">{{idx + 1}}. {{fruit}}
</view>
3. wx:key
:为循环项指定唯一的“身份证”
在进行列表渲染时,小程序框架需要一种方式来识别每个循环项,以便在数据变化时,能高效地更新DOM(只更新变化的部分,而不是重新渲染整个列表)。这个识别的凭证就是wx:key
。
wx:key
的重要性:
- 提升性能:有了
key
,小程序可以精确地知道哪个项是新增的、哪个是删除的、哪个只是移动了位置,从而进行最小化的渲染操作。 - 维持状态:如果你的循环项中包含
<input>
或<switch>
等有自身状态的组件,正确使用key
可以确保在列表更新后,这些组件的状态(如输入的内容)不会错乱。
如何设置wx:key
?
key
的值必须是列表中唯一的字符串或数字。通常有两种方式:
-
使用
*this
: 如果你的数组是一个简单的字符串或数字数组(成员本身就是唯一的),你可以用wx:key="*this"
。<view wx:for="{{['a', 'b', 'c']}}" wx:key="*this">{{item}}</view>
-
使用对象中的唯一属性: 如果你的数组是对象数组,强烈推荐使用对象中具有唯一性的属性(如
id
)作为key
。JS (准备数据):
Page({data: {users: [{ id: 1001, name: 'Alice' },{ id: 1002, name: 'Bob' },{ id: 1003, name: 'Charlie' }]} })
WXML (使用
id
作为key
):<view wx:for="{{users}}" wx:key="id">ID: {{item.id}}, 姓名: {{item.name}} </view>
最佳实践:始终为你的
wx:for
循环提供一个明确且唯一的wx:key
。如果你不提供,开发者工具会给出一个警告。
wx:if
vs hidden
:条件渲染的抉择
二、条件渲染允许我们根据条件来决定是否渲染某段WXML代码。小程序提供了两种方式来实现:wx:if
和hidden
。
1. wx:if
:真正的“条件编译”
wx:if
, wx:elif
, wx:else
构成了一套完整的条件判断逻辑,类似于JavaScript中的if...else if...else
。
wx:if="{{condition}}"
:当condition
为true
时,渲染该组件。wx:elif="{{condition2}}"
:当前一个wx:if
为false
时,判断condition2
。wx:else
:当所有前面的wx:if
和wx:elif
都为false
时,渲染该组件。
工作原理:
wx:if
是惰性的。如果条件为false
,小程序框架根本不会创建这块WXML对应的DOM节点。当条件由false
变为true
时,才会动态地创建并插入DOM。
动手实践 - 根据用户登录状态显示不同内容:
JS:
Page({data: {isLoggedIn: false},toggleLogin: function() {this.setData({ isLoggedIn: !this.data.isLoggedIn });}
})
WXML:
<button bindtap="toggleLogin">切换登录状态</button><view wx:if="{{isLoggedIn}}"><image src="/path/to/avatar.png"/><text>欢迎回来,尊贵的用户!</text>
</view>
<view wx:else><text>您当前未登录,请先登录。</text>
</view>
hidden
:简单的显示/隐藏切换
2. hidden="{{condition}}"
也用于控制组件的显隐。
- 当
condition
为true
时,组件被隐藏。 - 当
condition
为false
时,组件被显示。
工作原理:
与wx:if
不同,带有hidden
属性的组件始终会被渲染到页面中。hidden
只是简单地通过类似display: none;
的CSS样式来控制它的显示和隐藏。
wx:if
vs hidden
:我该用哪个?
3. 这是一个非常经典的面试题,也是开发中需要权衡的选择。
特性 | wx:if | hidden |
---|---|---|
初始渲染 | 如果条件为false ,不渲染,初始开销小 | 始终渲染,初始开销大 |
切换开销 | 切换时涉及DOM的创建和销毁,切换开销大 | 切换时只改变CSS属性,切换开销小 |
适用场景 | 运行时条件不常改变的场景 | 需要频繁切换显示/隐藏的场景 |
总结一下:
- 如果一个组件在应用的生命周期中,可能永远不会被显示(比如管理员才有的按钮),或者切换频率非常低(比如登录/未登录状态的切换),用
wx:if
更合适,因为它可以节省初始的渲染开销。 - 如果一个组件需要频繁地在显示和隐藏之间切换(比如一个加载中的提示、一个可折叠的面板),用
hidden
性能会更好,因为它避免了反复创建和销毁组件的开销。
三、<block>
:逻辑的“隐形”容器
有时候,你需要使用wx:for
循环渲染多个平级的标签,或者使用wx:if
控制多个标签的显隐。这时,如果你用一个<view>
来包裹它们,会多出一个不必要的DOM节点,可能会影响样式。
<block>
标签就是为了解决这个问题而生的。它是一个逻辑包裹容器,可以承载wx:for
或wx:if
等属性,但它本身不会被渲染成任何实际的UI元素。
示例:
<block wx:for="{{products}}" wx:key="id"><view class="product-title">{{item.name}}</view><view class="product-price">¥{{item.price}}</view>
</block>
上面的代码会渲染出一系列的<view>
对,但不会有一个额外的<block>
标签包裹它们。
结语
今天,我们掌握了小程序页面动态化的两大核心魔法:列表渲染和条件渲染。我们知道了:
- 使用
wx:for
和wx:key
来高效地渲染列表数据。 - 根据场景,在
wx:if
(控制渲染)和hidden
(控制显隐)之间做出明智的选择。 - 利用
<block>
标签来组织复杂的渲染逻辑,而不引入多余的UI结构。
现在,你的小程序已经具备了根据数据动态构建界面的能力,这是从简单页面走向复杂应用的一大步。
我们的应用已经能在一个页面内玩出很多花样了,但一个完整的应用绝不可能只有一个页面。那么,如何在多个页面之间跳转?如何传递参数?下一讲,我们将学习页面路由与导航,打通小程序内部的“任督二脉”。
我们下篇见!