Files
Neo-ZQYY/_DEL/wechat-miniprogram/steering/view-layer.md
2026-03-15 10:15:02 +08:00

309 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 视图层WXML / WXSS / WXS
> 官方文档https://developers.weixin.qq.com/miniprogram/dev/framework/view/
## WXML — 模板语法
### 数据绑定
```xml
<!-- 简单绑定 -->
<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
```xml
<!-- 基本用法:默认 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>
<!-- 值为 *thisitem 本身是唯一字符串或数字 -->
<switch wx:for="{{numberArray}}" wx:key="*this">{{item}}</switch>
```
**wx:key 的作用**:当数据改变触发重新渲染时,带有 key 的组件会被重新排序而非重新创建,保持自身状态(如 `<input>` 的输入内容、`<switch>` 的选中状态)。
### 条件渲染
```xml
<!-- 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
```xml
<!-- 定义模板 -->
<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'}}"/>
```
### 引用
```xml
<!-- 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 单位
rpxresponsive 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。
### 样式导入
```css
/* 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` | 伪元素 |
### 内联样式
```xml
<!-- style动态样式运行时解析尽量避免静态样式写在 style 中 -->
<view style="color:{{color}};"/>
<!-- class静态样式写在 class 中 -->
<view class="normal_view"/>
```
### 全局样式与局部样式
- `app.wxss` 为全局样式,作用于每个页面
- 页面的 `.wxss` 只对当前页面生效,会覆盖 `app.wxss` 中相同的选择器
## WXSWeiXin Script
WXS 是小程序的一套脚本语言,可以在 WXML 中使用。**WXS 运行在视图层**,比 JS 逻辑层快(不需要跨线程通信)。
```xml
<!-- 内联 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>
```
```javascript
// 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 中不能调用小程序 APIwx.xxx
```
**WXS 典型用途**
- 格式化数据(日期、金额、文本截断)
- 在视图层做简单计算,避免 setData 开销
- 响应事件WXS 事件响应iOS 上性能更好)
## 事件系统
### 事件分类
| 类型 | 说明 | 示例 |
|------|------|------|
| 冒泡事件 | 向父节点传递 | tap, longpress, touchstart, touchmove, touchend, touchcancel |
| 非冒泡事件 | 不向父节点传递 | submit, input, scroll 等组件特有事件 |
### 事件绑定
```xml
<!-- 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>
```
### 事件对象
```javascript
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
```xml
<!-- data-xxx 属性传递数据 -->
<view data-alpha-beta="1" data-alphaBeta="2" bindtap="handleTap">
Click
</view>
```
```javascript
handleTap(e) {
e.currentTarget.dataset.alphaBeta // "1"(连字符转驼峰)
e.currentTarget.dataset.alphabeta // "2"(大写转小写)
}
```
### mark基础库 2.7.1+
```xml
<!-- mark 可以在冒泡路径上所有节点收集 -->
<view mark:myMark="last" bindtap="bindViewTap">
<button mark:anotherMark="leaf" bindtap="bindButtonTap">按钮</button>
</view>
```
```javascript
bindButtonTap(e) {
e.mark // { myMark: "last", anotherMark: "leaf" }
// mark 会合并冒泡路径上所有的 mark
}
```
## 在线查询
如需更详细信息,可抓取:
- WXML 语法https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/
- WXSShttps://developers.weixin.qq.com/miniprogram/dev/framework/view/wxss.html
- WXShttps://developers.weixin.qq.com/miniprogram/dev/reference/wxs/
- 事件https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html