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

444 lines
9.1 KiB
Markdown
Raw Permalink 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.
# 自定义组件
> 官方文档https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/
基础库 1.6.3+ 支持。
## 创建自定义组件
一个自定义组件由 `json` `wxml` `wxss` `js` 四个文件组成。
```json
// my-component.json — 声明为组件
{ "component": true }
```
```xml
<!-- my-component.wxml -->
<view class="inner">
{{innerText}}
<slot></slot>
</view>
```
```css
/* my-component.wxss — 样式只作用于本组件 */
.inner { color: red; }
```
```javascript
// my-component.js
Component({
properties: {
innerText: {
type: String,
value: 'default value'
}
},
data: {
someData: {}
},
methods: {
customMethod() {}
}
})
```
### 使用自定义组件
```json
// 页面或组件的 .json
{
"usingComponents": {
"my-component": "/components/my-component/my-component"
}
}
```
```xml
<!-- 页面 wxml -->
<my-component inner-text="Some text">
<view>这里是插入到 slot 中的内容</view>
</my-component>
```
**注意事项**
- 标签名只能是小写字母、中划线、下划线的组合
- 组件和页面所在项目根目录名不能以 "wx-" 为前缀
- 使用 `usingComponents` 会使页面的 `this` 原型稍有差异(多了 `selectComponent` 等方法)
- 使用 `usingComponents` 时,`setData` 内容不会被深复制(性能优化)
## Component() 构造器
```javascript
Component({
// ===== 组件属性(外部传入) =====
properties: {
myProperty: {
type: String, // 类型String, Number, Boolean, Object, Array, null(任意)
value: '', // 默认值
observer(newVal, oldVal) {
// 属性变化时触发(已不推荐,建议用 observers
}
},
myProperty2: String // 简化定义
},
// ===== 组件内部数据 =====
data: {
someData: 'initial'
},
// ===== 生命周期(推荐写在 lifetimes 中) =====
lifetimes: {
created() {
// 组件实例刚被创建时
// 此时不能调用 setData通常用于给 this 添加自定义属性
},
attached() {
// 组件实例进入页面节点树时
// 大多数初始化工作在此进行
},
ready() {
// 组件在视图层布局完成后
},
moved() {
// 组件实例被移动到节点树另一个位置时
},
detached() {
// 组件实例被从页面节点树移除时
// 清理工作(如清除定时器)
},
error(err) {
// 组件方法抛出错误时(基础库 2.4.1+
}
},
// ===== 组件所在页面的生命周期 =====
pageLifetimes: {
show() {
// 页面被展示时
},
hide() {
// 页面被隐藏时
},
resize(size) {
// 页面尺寸变化时
},
routeDone() {
// 页面路由动画完成时(基础库 2.31.2+
}
},
// ===== 数据监听器(基础库 2.6.1+ =====
observers: {
'numberA, numberB'(numberA, numberB) {
// numberA 或 numberB 变化时触发
this.setData({ sum: numberA + numberB })
},
'some.subfield'(subfield) {
// 监听子数据字段
},
'arr[12]'(val) {
// 监听数组某一项
},
'some.field.**'(field) {
// 使用通配符监听所有子数据字段
},
'**'() {
// 监听所有 setData每次 setData 都触发,慎用)
}
},
// ===== 方法 =====
methods: {
onMyButtonTap() {
this.setData({ someData: 'new value' })
},
// 内部方法建议以下划线开头
_myPrivateMethod() {
this.setData({ 'A.B': 'myPrivateData' })
}
},
// ===== behaviors =====
behaviors: [],
// ===== 其他选项 =====
options: {
multipleSlots: true, // 启用多 slot默认只能一个
styleIsolation: 'isolated', // 样式隔离模式
pureDataPattern: /^_/, // 纯数据字段正则
virtualHost: true // 虚拟化组件节点(基础库 2.11.2+
},
// ===== 外部样式类 =====
externalClasses: ['my-class'],
// ===== 组件间关系 =====
relations: {},
// ===== 导出(配合 wx://component-export =====
export() {
return { myField: 'myValue' }
}
})
```
## 组件模板和样式
### 多 slot
```javascript
// 组件 js
Component({
options: { multipleSlots: true }
})
```
```xml
<!-- 组件 wxml -->
<view>
<slot name="before"></slot>
<view>组件内部内容</view>
<slot name="after"></slot>
</view>
<!-- 使用 -->
<my-component>
<view slot="before">before 内容</view>
<view slot="after">after 内容</view>
</my-component>
```
### 样式隔离 styleIsolation
```javascript
Component({
options: {
styleIsolation: 'isolated'
// 'isolated'(默认):组件样式完全隔离
// 'apply-shared':页面 wxss 样式会影响组件,但组件不影响页面
// 'shared':页面和组件样式互相影响
}
})
```
也可在 json 中配置:
```json
{ "styleIsolation": "isolated" }
```
### 外部样式类
```javascript
// 组件
Component({
externalClasses: ['my-class']
})
```
```xml
<!-- 组件 wxml -->
<view class="my-class">这段文本的颜色由外部决定</view>
<!-- 使用时 -->
<my-component my-class="red-text"/>
```
## 组件间通信
### 父 → 子properties
```xml
<my-component prop-a="{{dataA}}" prop-b="staticValue"/>
```
### 子 → 父triggerEvent
```javascript
// 子组件
Component({
methods: {
onTap() {
this.triggerEvent('myevent', { value: 'data' }, {
bubbles: false, // 是否冒泡
composed: false, // 是否穿越组件边界
capturePhase: false // 是否有捕获阶段
})
}
}
})
```
```xml
<!-- 父组件/页面 -->
<my-component bind:myevent="onMyEvent"/>
<!-- 或 bindmyevent="onMyEvent" -->
```
```javascript
// 父组件/页面
Page({
onMyEvent(e) {
e.detail // { value: 'data' }
}
})
```
### 父获取子实例selectComponent
```xml
<my-component id="the-id" class="the-class"/>
```
```javascript
const child = this.selectComponent('#the-id')
// 或 this.selectComponent('.the-class')
child.setData({ ... })
child.someMethod()
```
## behaviors代码复用
类似 mixins / traits。
```javascript
// my-behavior.js
module.exports = Behavior({
behaviors: [], // 可以引用其他 behavior
properties: {
myBehaviorProperty: { type: String }
},
data: {
myBehaviorData: {}
},
attached() {},
methods: {
myBehaviorMethod() {}
}
})
```
```javascript
// 组件中使用
const myBehavior = require('my-behavior')
Component({
behaviors: [myBehavior],
// 组件自身的 properties/data/methods 会与 behavior 合并
// 同名字段:组件 > behavior > 更早的 behavior
// 同名生命周期都会执行behavior 先于组件)
})
```
### 内置 behaviors
| behavior | 说明 |
|----------|------|
| `wx://form-field` | 使组件像表单控件form 可识别 |
| `wx://form-field-group` | form 识别组件内部所有表单控件2.10.2+ |
| `wx://form-field-button` | form 识别组件内部 button2.10.3+ |
| `wx://component-export` | 自定义 selectComponent 返回值2.2.3+ |
## 纯数据字段
不用于渲染的数据,不会参与 setData 传输,提升性能。
```javascript
Component({
options: {
pureDataPattern: /^_/ // 以 _ 开头的字段为纯数据
},
data: {
a: true, // 普通数据,参与渲染
_b: true // 纯数据,不参与渲染
}
})
```
## 组件间关系 relations
```javascript
// custom-ul
Component({
relations: {
'./custom-li': {
type: 'child',
linked(target) {}, // 子组件 attached 时
linkChanged(target) {},
unlinked(target) {} // 子组件 detached 时
}
}
})
// custom-li
Component({
relations: {
'./custom-ul': {
type: 'parent',
linked(target) {},
linkChanged(target) {},
unlinked(target) {}
}
}
})
```
**type 可选值**`parent` / `child` / `ancestor` / `descendant`
## 抽象节点 componentGenerics
```json
// selectable-group.json
{
"componentGenerics": {
"selectable": {
"default": "path/to/default"
}
}
}
```
```xml
<!-- selectable-group.wxml -->
<view wx:for="{{labels}}">
<selectable disabled="{{false}}"></selectable>
</view>
<!-- 使用时指定具体组件 -->
<selectable-group generic:selectable="custom-radio"/>
```
## 用 Component 构造器构造页面
```javascript
Component({
properties: {
paramA: Number, // 接收页面参数 ?paramA=123
paramB: String
},
methods: {
onLoad() {
this.data.paramA // 123
},
onShow() {},
onPullDownRefresh() {}
// 页面生命周期写在 methods 中
}
})
```
对应 json 需包含 `usingComponents`
```json
{ "usingComponents": {} }
```
好处:可以使用 behaviors 提取所有页面公用代码。
## 在线查询
如需更详细信息,可抓取:
- Component 参考https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html
- Behavior 参考https://developers.weixin.qq.com/miniprogram/dev/reference/api/Behavior.html
- 组件生命周期https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/lifetimes.html