3.1 WXML 是什么
WXML(WeiXin Markup Language)是微信小程序的模板语言,语法上类似 HTML,但有本质区别。WXML 不运行在浏览器中,没有 DOM 概念,所有标签都是小程序框架定义的组件。
WXML 有
- 数据绑定
{{变量}} - 条件渲染
wx:if - 列表渲染
wx:for - 模板复用
template - 事件绑定
bind*/catch* - 引用
import/include
WXML 没有
div/span/p等 HTML 标签- DOM API(document、window)
- script 标签(逻辑在 .js 中)
- link/style 标签(样式在 .wxss 中)
- HTML 全局属性(如 id 用于 CSS)
3.2 数据绑定
WXML 使用 {{expression}} 语法将 Page.data 中的数据绑定到模板,支持表达式运算、对象属性访问和方法调用(有限制)。
基础数据绑定
<!-- index.wxml -->
<!-- 绑定文本内容 -->
<view>{{message}}</view>
<text>你好,{{userInfo.nickname}}</text>
<!-- 绑定属性值(必须在引号内使用 {{}})-->
<image src="{{avatarUrl}}" mode="aspectFill"/>
<!-- 绑定布尔属性(注意:不能直接写 checked,要用 {{}} )-->
<checkbox checked="{{isChecked}}"/>
<!-- 表达式运算 -->
<view>总价:{{price * quantity}}</view>
<view>{{isVip ? '会员价' : '普通价'}}</view>
<view>{{index + 1}}. {{item.name}}</view>
<!-- 字符串拼接 -->
<view class="item {{active ? 'active' : ''}}">选项</view>
// index.js — 对应的 data
Page({
data: {
message: 'Hello, 小程序',
userInfo: { nickname: '张三', avatar: '' },
avatarUrl: 'https://example.com/avatar.jpg',
isChecked: true,
price: 99.9,
quantity: 3,
isVip: false,
active: true
}
})
WXML 的 {{}} 内只支持简单 JavaScript 表达式,不能调用自定义函数(如 {{formatDate(date)}} 是无效的)。需要格式化数据时,应在 setData 之前处理好再存入 data,或使用 WXS 模块。
3.3 条件渲染
WXML 提供两种条件渲染机制,适用于不同场景:
wx:if / wx:elif / wx:else
<!-- 完整的条件分支 -->
<view wx:if="{{orderStatus === 'pending'}}">待付款</view>
<view wx:elif="{{orderStatus === 'paid'}}">已付款</view>
<view wx:elif="{{orderStatus === 'shipped'}}">已发货</view>
<view wx:else>已完成</view>
<!-- block 包裹多个元素(不产生额外节点)-->
<block wx:if="{{isLogin}}">
<view>用户名:{{username}}</view>
<view>积分:{{points}}</view>
</block>
<block wx:else>
<button bindtap="goLogin">立即登录</button>
</block>
hidden 属性 vs wx:if
<!-- hidden 只是隐藏(display:none),元素仍然存在 -->
<view hidden="{{!showPanel}}">侧边面板</view>
<!-- wx:if 为 false 时,节点完全不创建 -->
<view wx:if="{{showModal}}">弹窗内容</view>
| 对比维度 | wx:if | hidden |
|---|---|---|
| DOM 节点 | false 时节点不存在 | 始终存在,只改变 display |
| 性能(频繁切换) | 较差(销毁/重建开销) | 较好(只改样式) |
| 性能(不频繁切换) | 较好(false 时无渲染开销) | 较差(始终占用内存) |
| 子组件生命周期 | 会触发 attached/detached | 不触发生命周期 |
| 适用场景 | 切换不频繁的大块内容 | 高频切换的简单元素 |
3.4 列表渲染
列表渲染是小程序开发中最常用的特性,用于将数组数据渲染为重复的 UI 结构。
基础 wx:for 用法
<!-- 默认:item 为数组元素,index 为下标 -->
<view wx:for="{{products}}" wx:key="id">
<text>{{index + 1}}. {{item.name}}</text>
<text>¥{{item.price}}</text>
</view>
<!-- 自定义变量名(推荐,代码更清晰)-->
<view
wx:for="{{cartItems}}"
wx:for-item="product"
wx:for-index="i"
wx:key="productId"
>
<text>{{i + 1}}. {{product.name}} × {{product.quantity}}</text>
</view>
<!-- 嵌套列表(分类+商品)-->
<view wx:for="{{categories}}" wx:for-item="cate" wx:key="cateId">
<text class="cate-title">{{cate.name}}</text>
<view
wx:for="{{cate.items}}"
wx:for-item="goods"
wx:key="goodsId"
>
<text>{{goods.name}}</text>
</view>
</view>
wx:key 的重要性
wx:key 告诉框架列表中每个节点的唯一标识,当列表数据变化(增删排序)时,框架可以复用已有节点而不是全部重新渲染,大幅提升性能。设置规则:
• wx:key="id" — item 的属性名(最推荐)
• wx:key="*this" — item 本身(适用于字符串/数字数组)
• 不设置 — 控制台警告,且列表性能差
3.5 模板(template)复用
当多个页面需要重复相同的 UI 片段时,可以用 template 定义可复用的模板。注意:template 只共享 WXML 结构,不创建独立的作用域(与自定义组件不同)。
定义和使用模板
<!-- templates/product-item.wxml -->
<template name="productItem">
<view class="product-card">
<image src="{{cover}}" mode="aspectFill"/>
<view class="info">
<text class="name">{{name}}</text>
<text class="price">¥{{price}}</text>
</view>
</view>
</template>
<!-- index.wxml — 使用模板 -->
<!-- 第一步:import 引入模板文件 -->
<import src="../../templates/product-item.wxml"/>
<!-- 第二步:is 指定模板名,data 传入数据 -->
<template
is="productItem"
data="{{...item}}"
/>
<!-- 批量渲染 -->
<view wx:for="{{products}}" wx:key="id">
<template is="productItem" data="{{...item}}"/>
</view>
import vs include
<template is="name"/> 引用<!-- include 示例 -->
<include src="../../templates/header.wxml"/>
<view class="content">...页面内容...</view>
<include src="../../templates/footer.wxml"/>
3.6 WXS 模块(渲染层脚本)
WXS(WeiXin Script)是可以在 WXML 中运行的脚本,能够在渲染层进行数据处理,避免跨线程通信。常用于数据格式化。
<!-- 内联 WXS 模块 -->
<wxs module="filters">
var formatPrice = function(price) {
return (parseFloat(price) / 100).toFixed(2)
}
var formatDate = function(timestamp) {
var d = new Date(timestamp)
return d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()
}
module.exports = {
formatPrice: formatPrice,
formatDate: formatDate
}
</wxs>
<!-- 使用 WXS 函数格式化数据 -->
<view>¥{{filters.formatPrice(item.priceInCents)}}</view>
<view>{{filters.formatDate(item.createdAt)}}</view>
WXS 使用的是类 ES5 语法(不支持 ES6+),不能调用小程序的 API(如 wx.request),也不能引用 JS 模块。它的运行环境与逻辑层 JS 是隔离的,仅适合做轻量的数据格式化和渲染层交互优化。