Skip to content

wxml 模板语法

1.1 数据绑定的 基本原则

  • 在 data 中定义数据
  • 在 WXML 中使用数据

1.2 在data中定义页面的数据

像这样:

js
Page({
  data: {
    // 字符串类型的数据
    info:'init data',
    // 数组类型的数据
    msgList: [{msg: 'hello'}, {msg: 'world'}]
  }
})

1.3 Mustache 语法的格式

把data 中的数据绑定到页面中渲染,使用 Mustache 语法 (双大括号)将变量包起来即可。

1.4 Mustache 语法的应用场景

  • 绑定内容
  • 绑定属性
  • 运算(包括三元运算、算数运算符)

1.4.1 动态绑定内容

页面的数据如下:

js
Page({
  data: {
    // 字符串类型的数据
    info:'init data',
    // 数组类型的数据
    msgList: [{msg: 'hello'}, {msg: 'world'}]
  }
})

结构为:

<image src="{{ imgSrc }}"></image>

1.4.2 三元运算

页面的数据如下:

js
Page({
  data: {
    randomNum: Math.random() * 10 // 生成10以内的随机数
  }
})

结构为:

<view> {{ randomNum >= 5 ? '随机数字 >= 5' : '随机数字 < 5' }} </view>

1.4.2 算数运算

页面的数据如下:

js
Page({
  data: {
    randomNum: Math.random().toFixed(2) // 生成一个带两位小数的随机数
  }
})

结构为:

<view>生成100以内的随机数 {{ randomNum * 100 }} </view>

1.5 事件绑定

事件是 渲染层到逻辑层的通讯方式 。通过事件可以将用户在渲染层产生的行为,反馈到逻辑层进行业务的处理。

image-20250717230415794

1.5.1小程序中常用的事件

事件类型事件名称触发时机备注
tap 点击事件bindtap点击事件(冒泡)最常用的点击事件
catchtap点击事件(阻止冒泡)需阻止事件冒泡时使用
bindlongpress长按事件长按触发(冒泡)
catchlongpress长按事件(阻止冒泡)需阻止事件冒泡时使用
touch 触摸事件bindtouchstart触摸开始触摸交互相关
bindtouchmove触摸移动触摸交互相关
bindtouchend触摸结束触摸交互相关
bindtouchcancel触摸取消(如被其他事件打断)
表单事件bindinput输入框内容实时变化实时监听输入内容
bindchange输入框内容变化(失去焦点时触发)非实时监听
bindfocus输入框获取焦点
bindblur输入框失去焦点
bindsubmit表单提交需在 <form> 组件上绑定
页面生命周期onLoad页面加载时触发(接收页面参数 options页面初始化时调用
onShow页面显示时触发(每次打开页面都会调用)
onReady页面初次渲染完成时触发(仅一次)
onHide页面隐藏时触发(如跳转到其他页面)
onUnload页面卸载时触发(如 redirectTonavigateBack 关闭页面)
onPullDownRefresh下拉刷新时触发(需在页面配置中启用 enablePullDownRefresh下拉刷新功能
onReachBottom上拉触底时触发(需配置 onReachBottomDistance上拉加载更多功能
onPageScroll页面滚动时触发(可获取滚动位置 scrollTop滚动监听

事件类型说明

  1. tap 点击事件
    • 包括普通点击 (bindtap/catchtap) 和长按 (bindlongpress/catchlongpress)。
    • catch 前缀会阻止事件冒泡到父组件。
  2. touch 触摸事件
    • 用于更精细的触摸交互(如滑动、拖拽等)。
    • 通常需要结合坐标计算实现自定义手势。
  3. 表单事件
    • 监听输入框或表单的交互行为。
    • bindinput 适合实时搜索,bindchange 适合最终提交验证。
  4. 页面生命周期事件
    • 控制页面加载、显示、隐藏等状态。
    • onPullDownRefreshonReachBottom 需在页面配置中启用。

1.5.2 事件对象的属性列表

当事件回调触发的时候,会收到一个事件对象 event ,它的详细属性如下表所示:

属性类别属性名类型说明适用场景
基础属性typestring事件类型(如 tapinput 等)所有事件
timeStampnumber事件生成时的时间戳(单位:毫秒)性能分析、事件计时
targetobject触发事件的组件的一些属性值集合区分事件源
currentTargetobject当前组件的一些属性值集合(可能不同于 target事件冒泡时区分当前组件
触摸事件特有touchesarray当前停留在屏幕上的触摸点信息的数组touchstart/move/end
changedTouchesarray触摸事件中发生变化的触摸点信息的数组(如从无到有、位置变化等)touchstart/move/end
表单事件特有detailobject额外的信息(如 input 事件的输入值、scroll 事件的滚动位置等)input/scroll/form 等事件
自定义数据datasetobject事件源组件上由 data- 开头的自定义属性组成的对象所有事件(组件间通信)
其他touches[0].clientX touches[0].clientYnumber触摸点的客户端屏幕坐标(X/Y)精确触摸位置计算
touches[0].pageX touches[0].pageYnumber触摸点的页面坐标(含滚动偏移,X/Y)考虑页面滚动的触摸位置
detail.x detail.ynumber某些事件(如 scroll)的滚动位置坐标滚动事件

1.5.3 target 和 currentTarget 的区别

target是触发该事件的源头组件 ,而 currentTarget 则是 当前事件所绑定的组件 。举例如下:

image-20250718112915569

点击内部的按钮时,点击事件以冒泡 的方式向外扩散,也会触发外层 view 的 tap 事件处理函数。

此时,对于外层的 view 来说:

  • e.target 指向的是触发事件的源头组件,因此, e.target 是内部的按钮组件
  • e.currentTarget 指向的是当前正在触发事件的那个组件,因此, e.currentTarget 是当前的 view 组

1.5.4 bindtap 的语法格式

在 小程序中,不存HTML 中的 onclick 鼠标点击事件,而是通过 tap 事件 来响应用户的触摸行为。 ① 通过 bindtap ,可以为组件绑定 tap 触摸事件,语法如下:

html
<button type="primary" bindtap="btnTapHandler">按钮</button>

② 在页面的 .js 文件中定义对应的事件处理函数,事件参数通过形参 eventevent(一般 简写成 e) 来接收:

js
Page({
  btnTapHandler(e){
    console.loe(e)
  }
})

1.5.5 在事件处理函数中为data中的数据赋值

通过调用 this.setData(dataObject) 方法,可以给页面data中的数据重新赋值:

js
// 页面的 .js 文件
Page({
  data: {
    count: 0
  },
  // 修改 count 的值
  changeCount() {
    this.setData({
      count: this.data.count + 1
    })
  }
})

更推荐将方法放在 methods 对象中(虽然直接定义在Page下也有效)

js
Page({
  data: { count: 0 },
  methods: {
    changeCount() {  // 更规范的写法
      this.setData({ count: this.data.count + 1 })
    }
  }
})
  • 优势:代码组织更清晰,与Vue等框架风格一致。

1.5.6 事件传参

小程序中的事件传参比较特殊,不能在绑定事件的同时为事件处理函数传递参数 。例如,下面的代码将不能正常工作:

html
<button type="primary" bindtap="btnHandle(123)">事件传参</button>

因为小程序会把 bindtap 的属性值,统一当作事件名称来处理,相当于要调用一个名称为 btnHandler(123)的事件处理函数。

正确的做法为,为组件提供 data-* 自定义属性传参,其中 * 代表参数名称:

html
<button bindtap="btnHandle" data-info="{{2}}">事件传参</button>

最终:

  • info 被解析为参数的名称
  • 数值 2 被解析为参数的值

事件处理函数中,通过 event.target.dataset.参数名即可获取到具体参数的值:

js
btnHandle(event){
    // dataset 是一个对象,包含了所有通过 data-* 传递过来的参数想
    console.log(event.target.dataset)
    // 通过 datase 可以访问到具体参数的值
    console.log(event.target.dataset.info)
  }

1.5.7 bindinput 的语法格式

在小程序中,通过 input 事件 来响应文本框的输入事件,语法格式如下: ① 通过 bindinput ,可以为文本框绑定输入事件:

html
<input bindinput="inputHandler" />

② 在页面的 .js 文件中定义事件处理函数:

js
inputHandler(e){
  // e.detail.value 是变化过后,文本框的最新值
  console.log(e.detail.value)
}

1.5.8 实现文本框和 data 之间的数据同步

定义数据:

js
Page({
  data:{
  	msg:'hello world'
  }
})

渲染结构:

html
<input value="{{msg}}" bindinput="iptHandler" />

美化样式:

css
input {
	border: 1px soild #eee;
	padding: 5px;
	margin: 5px;
	border-redius: 3px;
}

绑定 input 事件处理函数:

js
// 文本框内容改变事件
iptHandler(e){
	this.setData({
		// 通过 e.detail.value 获取到文本框的最新值
		msg:e.detail.value
	})
}

当用户在输入框输入内容时:

  1. 小程序框架会自动触发 bindinput 绑定的 iptHandler 函数。
  2. 框架会将一个事件对象 e 作为参数传入 iptHandler
  3. 这个 e 对象的 detail.value 属性已经包含了输入框的最新值(由小程序框架内部维护)。

1.6 条件渲染

1.6.1 wx:if

在小程序中,使用 wx:if="" 来判断是否需要渲染该代码块:

html
<view wx:if="{{condition}}">True</view>

也可以使用 wx:elifwx:else 添加判断分支:

html
<view wx:if="{{type === 1}}">男</view>
<view wx:elif="{{type === 2}}">女</view>
<view wx:else>保密</view>

如果要一次性控制多个组件的展示与隐藏,可以使用一个 <block> 标签将多个组件包裹起来,并在 <block> 上使用 wx:if 控制:

html
<block wx:if="{{true}}">
  <view>view</view>
  <view>view</view>
</block>

注意:<block> 并不是一个组件,它只是一个包裹性质的容器,不会在页面中做任何渲染。

1.6.2 hidden

小程序中,也可以使用 hidden="" 控制元素的显示与隐藏:

html
<view hidden="{{condition}}">条件为 true 隐藏,条件为 false 显示</view>

wx:if 与 hidden 的对比

  1. 运行方式不同:
  • wx:if 是以 动态创建和移除元素 的方式控制显示。
  • hidden 是以 切换样式(display: none/block) 的方式控制显示。
  1. 使用建议:
  • 频繁切换时,建议使用 hidden
  • 条件复杂时,建议使用 wx:if 搭配 wx:elifwx:else 来控制展示与隐藏。

1.7 列表渲染

1.7.1 wx:for

通过 wx:for 可以根据指定的数组,循环渲染重复的组件结构:

html
<view wx:for="{{array}}">
	索引是:{{index}} 当前项是:{{item}}
</view>

默认情况下,当前循环项的索引 用 index 表示; 当前循环项 用 item 表示。

1.7.2手动指定索引和当前项的变量名 *

  • 使用 wx:for for-index 可以指定 当前循环项的索引 的变量名

  • 使用 wx:for for-item 可以指定 当前项 的变量名 示例代码如下:

    html
    <view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
    	索引是:{{idx}} 当前项是:{{itemName}}
    </view>

1.7.3 wx:key 的使用

类似于 Vue 列表渲染中的 :key ,小程序在实现列表渲染时,也建议为渲染出来的列表项指定唯一的 key 值, 从而 提高渲染的效率 :

html
// data 数据
data: {
  userList: [
    { id: 1, name: '小红' },
    { id: 2, name: '小黄' },
    { id: 3, name: '小白' }
  ]
}

<!-- wxml 结构 -->
<view wx:for="{{userList}}" wx:key="id">{{item.name}}</view>

wxss 模板样式

2.1 基本概念

WXSS (WeiXin Style Sheets)是一套 样式语言 ,用于美化 WXML 的组件样式,类似于网页开发中的 CSS 。

WXSS 具有 CSS 大部分特性, 同时WXSS 还对 CSS 进行了扩充以及修改,以适应微信小程序的开发。 与 CSS 相比, WXSS 扩展的特性有:

  • rpx 尺寸单位
  • @import 样式导入

2.2 rpx

rpx(responsive pixel )是微信小程序独有的,用来 解决屏适配的尺寸单位 。

rpx的实现原理非常简单:鉴于不同设备屏幕的大小不同,为了实现屏幕的自动适配,rpx 把所有设备的屏幕,在宽度上等分为 750 份(即: 当前屏幕的总宽度为 750rpx)。

  • 在较小 的设备上, 1rpx 所代表的宽度较小
  • 在较大 的设备上, 1rpx 所代表的宽度较大

小程序在不同设备上运行的时候,会自动把rpx 的样式单位换算成对应的像素单位来渲染,从而实现屏幕适配。

2.3 rpx 与 px 之间的单位换算

rpx 与 px 的核心区别

单位全称特点适用场景
rpxresponsive pixel(响应式像素)根据屏幕宽度自动缩放,保证不同设备显示比例一致小程序中推荐优先使用,尤其是需要适配多种屏幕的场景(如布局、字体大小)
pxpixel(物理像素)固定物理像素值,不随屏幕变化用于需要精确控制像素的场景(如边框、阴影等细节)

rpx 与 px 的换算规则

小程序的 rpx 设计目标是:在所有设备上,750rpx 恰好等于屏幕宽度。 因此,换算公式为:

rpx=px×设计稿宽度(px)750

或反向换算:

px=rpx×750设计稿宽度(px)

常见场景示例

  1. 以 750px 宽度的设计稿为准(小程序官方推荐设计稿宽度):
    • 1px(设计稿) = 1rpx(小程序) (因为 750rpx = 750px,所以 1rpx = 1px
    • 例如:设计稿中一个按钮宽度为 150px,则小程序中直接写 width: 150rpx
  2. 以其他宽度(如 375px)的设计稿为准
    • 换算公式:1px(设计稿) = 2rpx(小程序) (因为 750rpx = 375px,所以 1rpx = 0.5px,即 1px = 2rpx
    • 例如:设计稿中一个元素高度为 100px,则小程序中需写 height: 200rpx

2.4 样式导入

使用 WXSS 提供的 @import 语法,可以导入外联的样式表。

@import 后跟需要导入的外联样式表的 相对路径 ,用 ;表示语句结束,示例如下:

css
//** common.wxss **//
.small-p {
  padding: 5px;
}
css
//** app.wxss **//
@import "common.wxss"
.middle-p {
  padding: 5px;
}

2.5 全局样式和局部样式

定义在 app.wxss 中的样式为全局样式 ,作用于每一个页面。

在页面的 .wxss 文件中定义的样式为局部样式 ,只作用于当前页面。

注意:

① 当局部样式和全局样式冲突时,根据 就近原则 ,局部样式会 覆盖 全局样式

② 当局部样式的 权重大于或等于 全局样式的权重时,才会覆盖全局的样式

Released under the MIT License.