当小程序页面越来越复杂时,组件化开发是提升代码复用性、可维护性的核心手段。这篇文章将带你掌握小程序自定义组件的创建、样式、数据监听、父子通信及 behaviors 复用,让你写出更优雅、高效的小程序代码。
一、创建并引用自定义组件
自定义组件是小程序的「可复用模块」,我们先从最基础的创建与引用开始。
1. 创建组件
在项目根目录新建 components 文件夹,每个组件都是一个独立文件夹,包含 .js/.json/.wxml/.wxss 四个文件:
json
// components/custom-btn/custom-btn.js
Component({
// 组件的属性、数据、方法等
})
2. 引用组件
引用分为全局引用和局部引用,通过 usingComponents 配置实现:
局部引用(推荐,仅当前页面可用)
在目标页面的 .json 中配置:
json
{
"usingComponents": {
"custom-btn": "/components/custom-btn/custom-btn" // 键名是组件标签名,值是组件路径
}
}
在页面 .wxml 中直接使用:
wxml
<custom-btn></custom-btn>
全局引用(所有页面可用)
在 app.json 中配置,一次配置全项目生效:
json
{
"usingComponents": {
"custom-btn": "/components/custom-btn/custom-btn"
}
}
二、组件样式隔离:控制样式影响范围
小程序组件默认样式隔离,通过 styleIsolation 选项修改隔离规则,避免样式污染。
1. 三种隔离模式
在组件 .js 的 options 中配置:
js
Component({
options: {
styleIsolation: 'isolated' // 默认值,完全隔离
// styleIsolation: 'apply-shared' // 组件可继承页面/全局样式,自身样式不向外影响
// styleIsolation: 'shared' // 组件与页面/全局样式互相影响(不推荐,易冲突)
}
})
isolated:组件样式完全独立,不受外部影响,也不影响外部。通用组件、基础组件
apply-shared: 组件可继承外部样式,但自身样式不泄露。业务组件,需复用全局主题
shared: 组件与外部样式互相渗透。特殊场景,谨慎使用
三、数据监听器:监听数据变化并响应
通过 observers 监听组件数据 / 属性变化,实现数据驱动的逻辑响应。
1. 基础用法
js
Component({
properties: {
count: Number
},
data: {
total: 0
},
observers: {
// 监听 count 属性变化,自动更新 total
'count': function(newVal, oldVal) {
this.setData({
total: newVal * 2
})
},
// 监听多个字段变化
'count, total': function(newCount, newTotal) {
console.log('count或total变化了', newCount, newTotal);
}
}
})
2. 监听对象 / 数组
支持监听对象属性或数组元素:
js
observers: {
'user.name': function(newName) {
console.log('用户名变为:', newName);
},
'list[0].title': function(newTitle) {
console.log('列表第一项标题变为:', newTitle);
}
}
四、纯数据字段:优化性能的小技巧
纯数据字段是不参与界面渲染的字段,通过 pureDataPattern 配置,减少不必要的 setData 性能消耗。
1. 配置与使用
js
Component({
options: {
pureDataPattern: /^_/ // 约定以下划线 _ 开头的字段为纯数据字段
},
data: {
_timer: null, // 纯数据字段,不渲染到页面
count: 0 // 普通字段,参与渲染
},
methods: {
startTimer() {
this.data._timer = setInterval(() => {
this.setData({ count: this.data.count + 1 })
}, 1000)
}
}
})
优势:纯数据字段修改时不会触发页面重渲染,适合存储定时器、临时状态等非 UI 数据。
五、父子组件通信:3 种核心方式
组件间通信是组件化的核心,小程序提供了三种父子通信方式,覆盖不同场景。
1. 方式一:属性绑定(父 → 子,单向传递)
父组件通过属性向子组件传递数据,子组件通过 properties 接收:
wxml
<!-- 父页面.wxml -->
<custom-btn title="点击我" count="{{count}}"></custom-btn>
js
// 子组件.js
Component({
properties: {
title: String,
count: Number
}
})
2. 方式二:事件绑定(子 → 父,事件通知)
子组件通过 triggerEvent 触发自定义事件,父组件通过 bind: 监听:
js
// 子组件.js
Component({
methods: {
handleClick() {
// 触发事件,向父组件传递数据
this.triggerEvent('myevent', { count: this.properties.count })
}
}
})
wxml
<!-- 父页面.wxml -->
<custom-btn bind:myevent="onMyEvent"></custom-btn>
js
// 父页面.js
Page({
onMyEvent(e) {
console.log('子组件传递的数据:', e.detail); // { count: ... }
}
})
3. 方式三:this.selectComponent()(父 → 子,直接调用)
父组件通过选择器获取子组件实例,直接调用子组件方法或访问数据:
wxml
<!-- 父页面.wxml -->
<custom-btn class="my-btn" id="btn"></custom-btn>
js
// 父页面.js
Page({
onLoad() {
// 通过 id 或 class 选择器获取子组件实例
const child = this.selectComponent('#btn')
// 直接调用子组件方法
child.handleClick()
// 直接访问子组件数据
console.log(child.properties.count)
}
})
六、behaviors:复用组件逻辑的利器
behaviors 是小程序的「代码复用模块」,类似 Mixin,可将多个组件的公共逻辑抽离复用。
1. 定义 behavior
新建 behaviors 文件夹,创建 behavior 文件:
js
// behaviors/common.js
module.exports = Behavior({
// 公共数据
data: {
commonData: '我是公共数据'
},
// 公共方法
methods: {
commonMethod() {
console.log('我是公共方法')
}
},
// 公共生命周期
created() {
console.log('behavior created')
}
})
2. 组件中引入 behavior
js
// 子组件.js
const commonBehavior = require('../../behaviors/common.js')
Component({
behaviors: [commonBehavior], // 引入behavior
methods: {
handleClick() {
this.commonMethod() // 直接调用behavior中的方法
console.log(this.data.commonData) // 直接访问behavior中的数据
}
}
})
特性:多个 behaviors 或组件与 behaviors 之间,同名数据 / 方法会按优先级覆盖,生命周期会依次执行。