8.4 KiB
8.4 KiB
视图层(WXML / WXSS / WXS)
官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/view/
WXML — 模板语法
数据绑定
<!-- 简单绑定 -->
<view>{{ message }}</view>
<!-- 组件属性绑定(需在双引号内) -->
<view id="item-{{id}}"></view>
<!-- 控制属性绑定 -->
<view wx:if="{{condition}}"></view>
<!-- 关键字绑定(注意 true/false 需要在 {{}} 内) -->
<checkbox checked="{{false}}"></checkbox>
<!-- ⚠️ 错误写法:checked="false" 会被当作字符串 "false",结果为 true -->
<!-- 运算 -->
<view>{{ a + b }} + {{ c }} + d</view>
<view>{{"hello " + name}}</view>
<view>{{object.key}} {{array[0]}}</view>
<!-- 三元运算 -->
<view hidden="{{flag ? true : false}}">Hidden</view>
<!-- 组合(数组) -->
<view wx:for="{{[zero, 1, 2, 3, 4]}}">{{item}}</view>
<!-- 组合(对象) -->
<template is="objectCombine" data="{{for: a, bar: b}}"></template>
<!-- 展开运算符 -->
<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
列表渲染 wx:for
<!-- 基本用法:默认 item 和 index -->
<view wx:for="{{array}}">
{{index}}: {{item.message}}
</view>
<!-- 自定义变量名 -->
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.message}}
</view>
<!-- 嵌套 -->
<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i">
<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j">
<view wx:if="{{i <= j}}">
{{i}} * {{j}} = {{i * j}}
</view>
</view>
</view>
<!-- ⚠️ wx:key 非常重要,用于列表项的唯一标识 -->
<!-- 值为字符串:item 的某个 property 名(该 property 值需唯一) -->
<switch wx:for="{{objectArray}}" wx:key="unique">{{item.id}}</switch>
<!-- 值为 *this:item 本身是唯一字符串或数字 -->
<switch wx:for="{{numberArray}}" wx:key="*this">{{item}}</switch>
wx:key 的作用:当数据改变触发重新渲染时,带有 key 的组件会被重新排序而非重新创建,保持自身状态(如 <input> 的输入内容、<switch> 的选中状态)。
条件渲染
<!-- wx:if / wx:elif / wx:else -->
<view wx:if="{{length > 5}}">1</view>
<view wx:elif="{{length > 2}}">2</view>
<view wx:else>3</view>
<!-- block wx:if(不会渲染为真实 DOM) -->
<block wx:if="{{true}}">
<view>view1</view>
<view>view2</view>
</block>
wx:if vs hidden:
wx:if是惰性的,条件为 false 时不渲染,切换时销毁/重建hidden始终渲染,只是切换显示/隐藏(类似 CSS display:none)- 频繁切换用
hidden,运行时条件不大可能改变用wx:if
模板 template
<!-- 定义模板 -->
<template name="msgItem">
<view>
<text>{{index}}: {{msg}}</text>
<text>Time: {{time}}</text>
</view>
</template>
<!-- 使用模板 -->
<template is="msgItem" data="{{...item}}"/>
<!-- 动态模板名 -->
<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
引用
<!-- import:引入目标文件中定义的 template -->
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
<!-- ⚠️ import 有作用域:只会引入目标文件中定义的 template,不会引入目标文件 import 的 template(不递归) -->
<!-- include:将目标文件除 <template/> <wxs/> 外的整个代码引入 -->
<include src="header.wxml"/>
<view>body</view>
<include src="footer.wxml"/>
WXSS — 样式
rpx 单位
rpx(responsive pixel):可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx。
| 设备 | rpx 换算 px | px 换算 rpx |
|---|---|---|
| iPhone5 | 1rpx = 0.42px | 1px = 2.34rpx |
| iPhone6 | 1rpx = 0.5px | 1px = 2rpx |
| iPhone6 Plus | 1rpx = 0.552px | 1px = 1.81rpx |
建议:开发时以 iPhone6 为视觉稿标准(750px 宽),1px = 1rpx。
样式导入
/* common.wxss */
.small-p { padding: 5px; }
/* app.wxss */
@import "common.wxss";
.middle-p { padding: 15px; }
选择器支持
| 选择器 | 示例 | 说明 |
|---|---|---|
| .class | .intro |
类选择器 |
| #id | #firstname |
ID 选择器 |
| element | view |
元素选择器 |
| element, element | view, checkbox |
群组选择器 |
| ::after | view::after |
伪元素 |
| ::before | view::before |
伪元素 |
内联样式
<!-- style:动态样式,运行时解析,尽量避免静态样式写在 style 中 -->
<view style="color:{{color}};"/>
<!-- class:静态样式写在 class 中 -->
<view class="normal_view"/>
全局样式与局部样式
app.wxss为全局样式,作用于每个页面- 页面的
.wxss只对当前页面生效,会覆盖app.wxss中相同的选择器
WXS(WeiXin Script)
WXS 是小程序的一套脚本语言,可以在 WXML 中使用。WXS 运行在视图层,比 JS 逻辑层快(不需要跨线程通信)。
<!-- 内联 WXS -->
<wxs module="m1">
var msg = "hello world";
module.exports.message = msg;
</wxs>
<view>{{m1.message}}</view>
<!-- 外部 WXS 文件 -->
<wxs src="./tools.wxs" module="tools"/>
<view>{{tools.msg}}</view>
<view>{{tools.bar(tools.FOO)}}</view>
// tools.wxs
var foo = "'hello world' from tools.wxs"
var bar = function(d) {
return d
}
module.exports = {
FOO: foo,
bar: bar,
}
// ⚠️ WXS 不支持 ES6 语法(箭头函数、let/const、解构等)
// ⚠️ WXS 中不能调用小程序 API(wx.xxx)
WXS 典型用途:
- 格式化数据(日期、金额、文本截断)
- 在视图层做简单计算,避免 setData 开销
- 响应事件(WXS 事件响应,iOS 上性能更好)
事件系统
事件分类
| 类型 | 说明 | 示例 |
|---|---|---|
| 冒泡事件 | 向父节点传递 | tap, longpress, touchstart, touchmove, touchend, touchcancel |
| 非冒泡事件 | 不向父节点传递 | submit, input, scroll 等组件特有事件 |
事件绑定
<!-- bind:不阻止冒泡 -->
<view bindtap="handleTap">Click me</view>
<view bind:tap="handleTap">Click me</view>
<!-- catch:阻止冒泡 -->
<view catchtap="handleTap">Click me</view>
<!-- mut-bind:互斥事件绑定(基础库 2.8.2+) -->
<view mut-bind:tap="handleTap">
<button mut-bind:tap="handleButtonTap">按钮</button>
</view>
<!-- 同一冒泡路径上的 mut-bind 只会有一个被触发 -->
<!-- capture-bind:捕获阶段绑定 -->
<view capture-bind:tap="handleCapture">
<view bindtap="handleTap">inner</view>
</view>
<!-- capture-catch:捕获阶段中断 -->
<view capture-catch:tap="handleCapture">
<view bindtap="handleTap">inner(不会触发)</view>
</view>
事件对象
Page({
handleTap(e) {
e.type // 事件类型,如 "tap"
e.timeStamp // 事件生成时的时间戳
e.target // 触发事件的源组件(可能是子组件)
e.currentTarget // 事件绑定的当前组件
e.detail // 额外信息,如 tap 的 { x, y }
e.touches // 触摸事件的触摸点信息数组
e.changedTouches // 变化的触摸点信息数组
e.mark // 事件标记(基础库 2.7.1+)
// target 和 currentTarget 的区别
e.target.id // 触发事件的组件 id
e.target.dataset // 触发事件的组件的 data-xxx 属性集合
e.currentTarget.id // 绑定事件的组件 id
e.currentTarget.dataset
}
})
dataset
<!-- data-xxx 属性传递数据 -->
<view data-alpha-beta="1" data-alphaBeta="2" bindtap="handleTap">
Click
</view>
handleTap(e) {
e.currentTarget.dataset.alphaBeta // "1"(连字符转驼峰)
e.currentTarget.dataset.alphabeta // "2"(大写转小写)
}
mark(基础库 2.7.1+)
<!-- mark 可以在冒泡路径上所有节点收集 -->
<view mark:myMark="last" bindtap="bindViewTap">
<button mark:anotherMark="leaf" bindtap="bindButtonTap">按钮</button>
</view>
bindButtonTap(e) {
e.mark // { myMark: "last", anotherMark: "leaf" }
// mark 会合并冒泡路径上所有的 mark
}
在线查询
如需更详细信息,可抓取:
- WXML 语法:https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/
- WXSS:https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxss.html
- WXS:https://developers.weixin.qq.com/miniprogram/dev/reference/wxs/
- 事件:https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html