4、框架基础:数据绑定、条件渲染(a:if)、列表渲染(a:for)—— 让页面“活”起来
各位同学,欢迎来到第四章。
前面几章我们搭好了架子,写了静态页面。但说实话,静态页面就像一张照片,好看是好看,但不会动。今天我们要聊的,就是让页面真正“活”起来的技术——数据绑定、条件渲染和列表渲染。
我个人习惯把这三样东西称为“框架三件套”。你想想看,一个动态页面无非就是:数据变了界面跟着变(数据绑定)、根据条件显示不同内容(条件渲染)、把一堆数据循环展示出来(列表渲染)。掌握了这三样,你就能写出真正可交互的小程序了。
4.1 数据绑定:让数据和界面“同步”
数据绑定,说白了就是“数据变了,页面自动变”。你不用手动去操作DOM,不用像以前写jQuery那样$('#xxx').text('新内容')。在支付宝小程序里,你只需要改数据,框架会自动帮你更新视图。
4.1.1 基础数据绑定
先看个最简单的例子。在页面的JS文件中,我们定义数据:
// pages/index/index.js
Page({
data: {
message: '你好,支付宝小程序!',
price: 99.8,
isVip: true
}
})
然后在AXML模板中,用双花括号 {{ }} 把数据包起来:
<view>{{ message }}</view>
<view>价格:{{ price }} 元</view>
<view>VIP用户:{{ isVip ? '是' : '否' }}</view>
这里要注意,{{ }} 里面可以写简单的表达式,比如三元运算符、算术运算、字符串拼接等。但别写太复杂的逻辑,比如循环、函数调用——这些应该在JS里处理好。
4.1.2 数据更新:this.setData()
数据绑定的核心是更新数据。在支付宝小程序里,更新数据必须用 this.setData() 方法。直接修改 this.data 是不会触发视图更新的——这是我刚入坑时踩过的坑。
// 正确做法
this.setData({
message: '数据已更新!',
price: 88.8
})
// 错误做法(不会触发视图更新)
this.data.message = '这样不行'
为什么会这样?因为 setData 会通知框架:“数据变了,快重新渲染!” 而直接赋值只是改了内存里的值,框架并不知道。
this.setData({ key: value }, () => { // 更新完成后的操作 })
4.1.3 对象和数组的更新
实际项目中,我们经常要更新对象里的某个字段,或者数组里的某个元素。这时候有个小技巧:
// 更新对象
this.setData({
'user.name': '张三',
'user.age': 25
})
// 更新数组元素
this.setData({
'list[0].title': '第一项的新标题'
})
用路径字符串的方式,可以精准更新深层数据,不用把整个对象都传进去。我在项目中处理复杂表单时,这个技巧帮我省了不少代码量。
4.2 条件渲染:a:if 和 a:elif 和 a:else
条件渲染,就是根据条件决定某个元素显示还是隐藏。支付宝小程序提供了 a:if、a:elif、a:else 三个指令。
4.2.1 基本用法
<view a:if="{{ score >= 90 }}">优秀</view>
<view a:elif="{{ score >= 60 }}">及格</view>
<view a:else>不及格</view>
这段代码会根据 score 的值,只显示其中一个 view。注意 a:elif 和 a:else 必须紧跟在 a:if 后面,中间不能有其他元素。
4.2.2 a:if 与 hidden 的区别
很多新手会问:用 a:if 和用 hidden 属性有什么区别?
| 对比项 | a:if | hidden |
|---|---|---|
| 渲染方式 | 条件为 false 时,元素不渲染(DOM中不存在) | 条件为 false 时,元素隐藏(display: none) |
| 切换开销 | 大(需要创建/销毁DOM) | 小(只切换CSS) |
| 适用场景 | 条件不频繁切换,或初始条件为 false | 条件频繁切换,或初始条件为 true |
简单来说:如果某个模块很少切换显示状态,用 a:if 更省资源;如果频繁切换(比如点击按钮显示/隐藏),用 hidden 性能更好。
4.3 列表渲染:a:for
列表渲染,就是把一个数组循环渲染到页面上。这是做列表页、商品展示、评论列表等场景的必备技能。
4.3.1 基本用法
<view a:for="{{ items }}" a:key="id">
{{ index }} - {{ item.name }}
</view>
这里有几个关键点:
a:for绑定一个数组- 默认情况下,当前项用
item表示,索引用index表示 a:key用来提高渲染性能,建议每次都加上
4.3.2 自定义变量名
如果 item 和 index 与其他变量冲突,可以用 a:for-item 和 a:for-index 重命名:
<view a:for="{{ users }}" a:for-item="user" a:for-index="idx" a:key="user.id">
{{ idx + 1 }}. {{ user.name }} - {{ user.age }}岁
</view>
我个人习惯在嵌套循环时一定要重命名,否则内层循环的 item 会覆盖外层,很容易出 bug。
4.3.3 a:key 的重要性
很多初学者会忽略 a:key,觉得不加也能跑。确实能跑,但性能会差很多。
为什么?因为框架需要知道哪些列表项是新增的、哪些是删除的、哪些是移动的。如果没有 a:key,框架只能按索引来对比,一旦列表顺序变了,它可能会把整个列表重新渲染。加上 a:key 后,框架就能精准地只更新变化的部分。
4.3.4 列表嵌套与复杂场景
实际项目中,列表嵌套很常见。比如一个分类列表,每个分类下又有商品列表:
<view a:for="{{ categories }}" a:for-item="category" a:key="category.id">
<view>{{ category.name }}</view>
<view a:for="{{ category.products }}" a:for-item="product" a:key="product.id">
{{ product.name }} - ¥{{ product.price }}
</view>
</view>
这里要注意,内层循环的 item 和 index 会覆盖外层,所以必须用 a:for-item 和 a:for-index 重命名。否则内层拿到的 item 是商品对象,外层拿到的 item 也是商品对象——这就乱套了。
4.4 综合实战:一个简单的商品列表
好了,理论讲完了。我们来写一个综合例子,把今天学的三个知识点串起来。
假设我们要做一个商品列表页,有以下几个功能:
- 展示商品列表(列表渲染)
- 根据库存显示“有货”或“缺货”(条件渲染)
- 点击商品切换选中状态(数据绑定)
先看数据:
Page({
data: {
products: [
{ id: 1, name: '蓝牙耳机', price: 199, stock: 10, selected: false },
{ id: 2, name: '充电宝', price: 89, stock: 0, selected: false },
{ id: 3, name: '数据线', price: 29, stock: 50, selected: false }
]
},
toggleSelect(e) {
const id = e.currentTarget.dataset.id
const products = this.data.products.map(item => {
if (item.id === id) {
return { ...item, selected: !item.selected }
}
return item
})
this.setData({ products })
}
})
再看模板:
<view a:for="{{ products }}" a:for-item="product" a:key="product.id"
class="product-item {{ product.selected ? 'selected' : '' }}"
data-id="{{ product.id }}" bindtap="toggleSelect">
<view>{{ product.name }}</view>
<view>¥{{ product.price }}</view>
<view a:if="{{ product.stock > 0 }}" class="in-stock">有货</view>
<view a:else class="out-of-stock">缺货</view>
</view>
这个例子虽然简单,但包含了今天讲的三个核心知识点。你想想看,如果没有框架,你要手动操作DOM来更新每个商品的选中状态、库存显示——那得写多少代码?
4.5 避坑指南
最后,分享几个我实际项目中遇到的坑:
- setData 的数据量不要太大。 单次 setData 的数据量建议控制在 1MB 以内,否则可能引起页面卡顿。如果数据量很大,考虑分页加载。
- a:key 的值不要用 index。 前面说过了,index 不稳定。用唯一 id 最靠谱。
- 条件渲染不要和 hidden 混用。 同一个元素,要么用 a:if,要么用 hidden,别两个都用,逻辑会乱。
- 列表渲染时,注意 this 指向。 在事件处理函数中,this 指向 Page 实例,但在回调函数或箭头函数中,this 可能会丢失。我习惯用箭头函数或者提前保存
const that = this。
好了,这一章的内容就到这里。数据绑定、条件渲染、列表渲染,这三个基础操作你掌握了,就能写出大部分动态页面了。下一章我们会聊事件处理——怎么响应用户的点击、输入等操作。到时候你会发现,这三样东西和事件处理结合起来,才是真正的“活”页面。
去写代码吧,动手试试。光看是学不会的。