1
This commit is contained in:
443
_DEL/wechat-miniprogram/steering/custom-component.md
Normal file
443
_DEL/wechat-miniprogram/steering/custom-component.md
Normal file
@@ -0,0 +1,443 @@
|
||||
# 自定义组件
|
||||
|
||||
> 官方文档: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 识别组件内部 button(2.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
|
||||
Reference in New Issue
Block a user