4、自定义组件开发(上):Component 构造器、properties 与 data、组件生命周期、组件通信
好,咱们今天聊聊自定义组件开发的上半部分。说实话,小程序开发里最让我觉得「有成就感」的,就是封装组件。你想想看,一个写好的组件,能在项目里到处复用,多爽。
但组件开发也有不少坑。我刚开始做的时候,就经常搞混 properties 和 data 的用法。嗯,今天咱们就把这些基础打牢。
4.1 Component 构造器:组件的「身份证」
每个自定义组件,都得用 Component 构造器来注册。说白了,它就是告诉小程序:「嘿,这是一个组件,你要按组件的方式来对待它」。
// components/my-component/my-component.js
Component({
behaviors: [],
properties: {},
data: {},
lifetimes: {},
methods: {}
})
我个人习惯,写组件时一定会把 methods 放在最后。为什么?因为 methods 里的方法最多,放最后不容易看花眼。
4.2 properties 与 data:组件的「输入」和「状态」
这两个概念,我见过太多人搞混了。咱们用一句话说清楚:
- properties:外部传进来的数据,是组件的「输入」
- data:组件内部自己用的数据,是组件的「状态」
举个例子你就明白了:
// 组件定义
Component({
properties: {
title: {
type: String,
value: '默认标题'
},
count: {
type: Number,
value: 0
}
},
data: {
internalCount: 0,
isVisible: true
}
})
我在项目中遇到过一个问题:有人把 properties 当 data 用,直接在组件内部修改 properties 的值。结果呢?父组件的数据也跟着变了,整个页面乱套了。
observers 监听变化,或者通过事件通知父组件去改。
4.3 组件生命周期:组件从生到死
组件的生命周期,说白了就是「组件从创建到销毁,中间经历了什么」。我刚开始学的时候,觉得生命周期很抽象。后来做多了才发现,它就是几个固定的时间点。
| 生命周期 | 触发时机 | 常见用途 |
|---|---|---|
| created | 组件实例刚被创建 | 初始化数据,但还不能操作界面 |
| attached | 组件被挂载到页面 | 可以获取节点信息,发起网络请求 |
| ready | 组件布局完成 | 可以获取节点宽高,做动画 |
| moved | 组件被移动 | 少用,但某些场景下有用 |
| detached | 组件被销毁 | 清理定时器、取消订阅 |
写生命周期的时候,我建议用 lifetimes 对象来定义:
Component({
lifetimes: {
created() {
console.log('组件创建了');
this.initData = { /* 初始化数据 */ };
},
attached() {
console.log('组件挂载了');
this.fetchData();
},
ready() {
console.log('组件准备好了');
this.getNodeInfo();
},
detached() {
console.log('组件销毁了');
clearInterval(this.timer);
}
}
})
setData!因为此时组件还没挂载到页面。我见过有人在这里写 setData,结果数据没更新,排查了半天。
4.4 组件通信:组件之间的「对话」
组件不是孤岛,它们需要互相通信。小程序里,组件通信主要有三种方式:
4.4.1 父传子:properties
这个最简单,父组件通过属性传值:
<!-- 父组件使用子组件 -->
<my-component title="你好" count="{{pageCount}}" />
子组件用 properties 接收就行。嗯,这里要注意:如果传的是对象,记得用 observer 监听变化。
4.4.2 子传父:triggerEvent
子组件想告诉父组件「我这边发生了什么事」,就用 triggerEvent:
// 子组件内部
methods: {
onTap() {
this.triggerEvent('myevent', { value: 123 });
}
}
<!-- 父组件监听事件 -->
<my-component bind:myevent="onMyEvent" />
我曾经犯过一个错:事件名用了驼峰命名,比如 myEvent。结果在 WXML 里怎么都监听不到。后来才发现,小程序里事件名要用小写加连字符,比如 my-event。
event.detail 获取。这个细节很多人忽略,结果拿不到数据。
4.4.3 兄弟组件通信:通过父组件中转
两个兄弟组件之间怎么通信?我一般用父组件做「中间人」:
- 子组件A 触发事件给父组件
- 父组件更新数据
- 数据通过 properties 传给 子组件B
说白了就是「A告诉爸爸,爸爸告诉B」。虽然绕了点,但这是最稳妥的方式。
4.5 实战小技巧:组件开发的「肌肉记忆」
最后,分享几个我写组件时的习惯:
- 命名规范:组件名用连字符,比如
my-component,别用驼峰 - 数据隔离:组件内部的数据,尽量用
data管理,别污染全局 - 生命周期清理:在
detached里一定要清理定时器和监听器,不然内存泄漏 - 代码注释:properties 的每个字段都写上注释,别人用你组件时能看懂
好了,这一章的内容就到这。下一章咱们聊聊组件的高级用法,包括插槽、混入和组件间的复杂通信。到时候我会分享一个我踩过的「大坑」,保证让你印象深刻。