在小程序中,创建组件需要定义组件的结构、样式和行为。以下是一个简单的组件目录结构:
|- components
|- custom-component
|- custom-component.js
|- custom-component.json
|- custom-component.wxml
|- custom-component.wxss
引用组件可以通过在页面的 .json
文件中配置 usingComponents
字段,然后在页面的 .wxml
文件中以标签的形式引用组件:
pages/index/index.json:
{
"usingComponents": {
"custom-component": "/components/custom-component/custom-component"
}
}
pages/index/index.wxml:
<view>
<custom-component></custom-component>
</view>
局部引用组件是指将组件引入到某个页面或组件内,而不是全局引用。这样做可以提高代码的灵活性和复用性。
pages/index/index.json:
{
"usingComponents": {
"custom-component": "/components/custom-component/custom-component"
}
}
pages/index/index.wxml:
<view>
<custom-component></custom-component>
</view>
全局引用组件是指在整个小程序中都可以使用该组件,不需要在每个页面或组件内单独引用。
app.json:
{
"usingComponents": {
"custom-component": "/components/custom-component/custom-component"
}
}
pages/index/index.wxml:
<view>
<custom-component></custom-component>
</view>
全局引用和局部引用各有优势,全局引用适用于在整个小程序中都需要使用的组件,而局部引用适用于只在某个页面或组件内使用的组件。
组件和页面在小程序中有一些区别,包括生命周期函数的执行时机和组件的作用域。理解这些区别有助于更好地利用自定义组件进行开发。
小程序中的组件样式是默认隔离的,即组件内部的样式不会影响到外部页面或组件。这种隔离有助于保持代码的独立性。
在使用组件样式隔离时,需要注意一些细节,例如如何正确引用外部样式。
开发者可以根据实际需求修改组件的样式隔离选项,灵活控制样式的作用范围。
可选值 | 默认值 | 描述 |
---|---|---|
isolated | true | 组件样式仅对组件生效,不影响外部样式。 |
apply-shared | false | 组件样式对组件生效,同时会影响引入组件的外部样式。 |
shared | false | 组件样式对组件生效,同时也会影响引入组件的外部样式,且外部样式对组件也生效。 |
组件内部可以定义 data
数据,用于存储组件的状态信息。
custom-component.js:
Component({
data: {
count: 0
},
// other properties and methods
})
methods
字段用于定义组件的方法,这些方法可以在组件内被调用。
custom-component.js:
Component({
data: {
count: 0
},
methods: {
increaseCount() {
this.setData({
count: this.data.count + 1
});
}
}
// other properties
})
properties
字段用于定义组件的属性,属性可以由组件外部传入,从而实现组件与外部的数据交互。
custom-component.json:
{
"component": true,
"properties": {
"title": {
"type": String,
"value": "Default Title"
}
}
}
理解 data
和 properties
的区别是使用自定义组件的关键,它们分别用于组件内部的状态管理和与外部数据的交互。
在组件内部可以使用 setData
方法修改 properties
的值,从而实现动态更新组件的属性。
custom-component.js:
Component({
properties: {
title: {
type: String,
value: "Default Title",
observer: function (newVal, oldVal) {
console.log('title changed', newVal, oldVal);
}
}
},
methods: {
changeTitle() {
this.setData({
title: "New Title"
});
}
}
// other properties
})
数据监听器用于监听组件内部 data
或 properties
的变化,当数据发生变化时触发相应的操作。
custom-component.js:
Component({
data: {
count: 0
},
observers: {
'count': function (newVal, oldVal) {
console.log('count changed', newVal, oldVal);
}
},
// other properties and methods
})
通过定义监听器函数,可以在数据变化时执行自定义的逻辑。
数据监听器不仅可以监听基本类型的数据变化,还可以监听对象属性的变化,实现
更精细化的数据控制。
custom-component.js:
Component({
data: {
user: {
name: 'John',
age: 25
}
},
observers: {
'user.name': function (newVal, oldVal) {
console.log('user name changed', newVal, oldVal);
}
},
// other properties and methods
})
纯数据字段是一种特殊的数据形式,用于在组件内定义一些纯粹的数据,不参与视图层的渲染。
纯数据字段的使用规则相对简单,只需要在组件的 json
文件中声明即可。
custom-component.json:
{
"component": true,
"pureData": {
"fieldName": "fieldValue"
}
}
通过使用纯数据字段,可以改造数据监听器,使得组件更加清晰和易维护。
custom-component.json:
{
"component": true,
"pureData": {
"isListening": false
},
"observers": {
'isListening': function (newVal) {
if (newVal) {
console.log('Start listening');
// Start listening logic
} else {
console.log('Stop listening');
// Stop listening logic
}
}
}
}
小程序中,组件有一系列的生命周期函数,包括 created
、attached
、ready
、moved
、detached
等。
custom-component.js:
Component({
lifetimes: {
created() {
console.log('component created');
},
attached() {
console.log('component attached');
},
ready() {
console.log('component ready');
},
moved() {
console.log('component moved');
},
detached() {
console.log('component detached');
}
},
// other properties and methods
})
了解组件的主要生命周期函数有助于合理地处理组件的初始化、渲染和销毁过程。
lifetimes
节点用于定义组件的生命周期函数,包括 created
、attached
、ready
、moved
、detached
等。
组件所在页面的生命周期指的是组件在页面中的生命周期,包括 show
、hide
等。
custom-component.js:
Component({
pageLifetimes: {
show() {
console.log('component show');
},
hide() {
console.log('component hide');
}
},
// other properties and methods
})
通过 pageLifetimes
节点,可以定义组件所在页面的生命周期函数,实现组件与页面的协同工作。
在页面生命周期函数中,可以实现一些动态的操作,例如生成随机的 RGB 颜色值,为用户提供更丰富的交互体验。
custom-component.js:
Component({
pageLifetimes: {
show() {
const randomColor = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)})`;
console.log('generated random color', randomColor);
}
},
// other properties and methods
})
插槽是一种用于在组件内部承载内容的机制,使得组件可以更加灵活地适应不同的使用场景。
custom-component.wxml:
<view class="container">
<view class="header">Header</view>
<slot></slot>
<view class="footer">Footer</view>
</view>
组件可以定义单个插槽,用于承载外部传入的内容。
index.wxml:
<custom-component>
<view>Content Goes Here</view>
</custom-component>
通过启用多个插槽,可以支持更复杂的内容布局和组合。
custom-component.wxml:
<view class="container">
<view class="header">Header</view>
<slot name="content"></slot>
<view class="footer">Footer</view>
<slot name="footer"></slot>
</view>
在组件内部,可以通过定义多个插槽,为不同的内容提供不同的展示方式。
index.wxml:
<custom-component>
<view slot="content">Content Goes Here</view>
<view slot="footer">Custom Footer</view>
</custom-component>
在页面中使用组件时,可以根据需要传入不同的内容到不同的插槽中,实现更灵活的布局。
父子组件之间可以通过属性绑定、事件绑定和获取组件实例等方式进行通信,实现数据的传递和操作的触发。
通过属性绑定,父组件可以向子组件传递数据,实现数据的共享。
parent-component.wxml:
<child-component title="{{parentTitle}}"></child-component>
child-component.js:
Component({
properties: {
title: String
},
// other properties and methods
})
通过事件绑定,子组件可以向父组件发送事件,触发父组件中的相应逻辑。
child-component.js:
Component({
methods: {
onTap() {
this.triggerEvent('customEvent', { data: 'Hello from Child' });
}
}
// other properties
})
parent-component.wxml:
<child-component bind:customEvent="onChildEvent"></child-component>
parent-component.js:
Page({
onChildEvent(event) {
console.log('Received custom event from child:', event.detail.data);
}
// other methods
})
通过获取组件实例,可以直接调用组件的方法,实现更直接的通信方式。
parent-component.js:
Page({
onReady() {
const childComponent = this.selectComponent('#child');
childComponent.doSomething();
}
// other methods
})
parent-component.wxml:
<child-component id="child"></child-component>
Behaviors 是一种可复用的代码块,通过引入 behaviors,可以将一组方法、数据和生命周期函数注入到组件中。
Behaviors 通过混入的方式工作,将 behaviors 中的内容合并到组件中,实现代码的复用。
在小程序中,可以创建自定义的 behavior,定义其中的方法和数据。
custom-behavior.js:
module.exports = Behavior({
data: {
behaviorData: 'This is from behavior'
},
methods: {
behaviorMethod() {
console.log('Behavior method');
}
}
})
通过在组件的 behaviors
字段中导入并使用 behavior,实现代码的重用和模块化。
custom-component.js:
const customBehavior = require('/path/to/custom-behavior');
Component({
behaviors: [customBehavior],
// other properties and methods
})
可用的节点 | 类型 | 是否必填 | 描述 |
---|---|---|---|
created | Function | 否 | 组件生命周期函数,在组件实例刚刚被创建时执行。 |
attached | Function | 否 | 组件生命周期函数,在组件实例进入页面节点树时执行。 |
ready | Function | 否 | 组件生命周期函数,在组件布局完成后执行。 |
moved | Function | 否 | 组件生命周期函数,在组件实例被移动到节点树另一个位置时执行。 |
detached | Function | 否 | 组件生命周期函数,在组件实例被从页面节点树移除时执行。 |
data | Object | 否 | 组件的内部数据,用于页面渲染。 |
methods | Object | 否 | 组件的方法,可以在页面内调用。 |
properties | Object | 否 | 组件的属性,用于接收父组件传递的数据。 |
lifetimes | Object | 否 | 组件的生命周期函数集合,包括 created、attached、ready、moved、detached。 |
pageLifetimes | Object | 否 | 组件所在页面的生命周期函数集合,包括 show、hide。 |
definitionFilter | Function | 否 | 用于过滤 behaviors 中定义的字段,返回 true 表示保留,返回 false 表示过滤。 |
当组件和 behavior 中存在同名字段时,小程序有一套规则来确定最终的取值,包括覆盖和组合的方式。
传统的异步 API 多采用回调函数的方式,但这种方式存在回调地狱、可读性差等问题。
API Promise 化是指将原本使用回调函数的异步 API 转化为返回 Promise 对象的形式,以更直观、便捷地处理异步操作。
使用 miniprogram-api-promise
这个第三方的 npm 包的 promisifyAll
方法,可以实现将小程序原生的异步 API 转化为 Promise 化的形式。
首先,安装 miniprogram-api-promise
:
npm install miniprogram-api-promise
然后,在小程序代码中使用:
//1.在小程序入口文件中调用一次 promisifyAll()方法
import { promisifyAll } from 'miniprogram-api-promise'
//2.声明一个常量,为一个空对象
const wxp = wx.p = {}
//3.调用 promisifyAll()方法
promisifyAll(wx, wxp)
wx
全局对象上定义一个属性 p
让他和 wxp
指向同一个空对象promisifyAll
: 做的事就是将 wx
拥有的属性方法都 copy
并改造了一份给了 wxp
这个对象//使用
async getInfo () {
const { data: res } = await wx.p.request({
url: 'https://www.escook.cn/api/get',
method: 'GET',
data: {
name: 'zs',
age: 19
}
})
// res 处理
console.log(res)
}
通过这种方式,可以更清晰、简洁地处理小程序的异步 API 调用。
全局数据共享是指在小程序中,使数据能够在不同页面或组件之间进行共享,以便实现全局状态的管理和同步更新。
在小程序中,有多种全局数据共享方案,其中之一是使用第三方库 MobX。MobX 是一个简单、可扩展的状态管理库,可以帮助实现全局数据的响应式更新和共享。
首先,安装 MobX 及其相关的包:
npm install mobx mobx-miniprogram
创建一个 MobX 的 Store 实例,用于管理全局数据:
// store.js
const { observable, action } = require('mobx-miniprogram');
class AppStore {
@observable globalData = {
userInfo: null,
// other global data
};
@action setUserInfo(userInfo) {
this.globalData.userInfo = userInfo;
}
}
module.exports = new AppStore();
在需要使用全局数据的页面中,将 Store 中的成员绑定到页面:
// index.js
const app = getApp();
const store = require('../../store');
Page({
onLoad() {
this.setData({
userInfo: app.store.globalData.userInfo,
});
// 监听 globalData 的变化
this.dispose = store.observe(() => {
this.setData({
userInfo: app.store.globalData.userInfo,
});
});
},
onUnload() {
// 移除监听
this.dispose();
},
});
在页面中可以直接使用 Store 中的成员:
<!-- index.wxml -->
<view>{{ userInfo.nickName }}</view>
在需要使用全局数据的组件中,也可以将 Store 中的成员绑定到组件:
// custom-component.js
const store = require('../../store');
Component({
lifetimes: {
attached() {
this.setData({
userInfo: store.globalData.userInfo,
});
// 监听 globalData 的变化
this.dispose = store.observe(() => {
this.setData({
userInfo: store.globalData.userInfo,
});
});
},
detached() {
// 移除监听
this.dispose();
},
},
});
在组件中同样可以直接使用 Store 中的成员:
<!-- custom-component.wxml -->
<view>{{ userInfo.nickName }}</view>
通过以上步骤,就实现了在小程序中使用 MobX 进行全局数据的共享和响应式更新。
分包是指将小程序项目划分成不同的子包,每个子包都可以包含页面、组件、资源文件等,实现模块化管理和按需加载。
在进行分包前,项目可能是单一的整体,包含全部页面和资源。
分包后,项目会被划分为主包和多个子包,每个子包可以包含特定的功能模块。
小程序在启动时会先下载主包,然后在需要时再下载子包。子包是按需加载的,用户访问对应的页面或组件时才会下载相关子包。
每个分包的体积不能超过 2MB,超过会导致分包加载失败。
在小程序的 app.json
文件中使用 subpackages
字段配置分包信息,指定每个分包的路径和名字。
{
"pages": [
"pages/index/index"
],
"subpackages": [
{
"root": "subpackage1",
"pages": [
"pages/subpage1/index",
"pages/subpage1/detail"
]
},
{
"root": "subpackage2",
"pages": [
"pages/subpage2/index",
"pages/subpage2/detail"
]
}
]
}
主包中包含 app.json
、app.js
、app.wxss
、project.config.json
等文件,每个分包下都有一个独立的 package.json
。
在主包中,可以直接引用主包和其他分包的页面和组件。在分包中,只能引用自己分包内的页面和组件。
独立分包是指一个分包中包含了完整的小程序结构,可以独立运行。主包和其他分包可以引用独立分包内的页面和组件。
独立分包可以包含完整的小程序结构,具备更强的独立性。普通分包只能包含部分页面和资源。
适用于某个功能模块比较独立,可以独立运行的场景。
在 app.json
的 subpackages
中配置 "independent": true
:
{
"subpackages": [
{
"root": "independent-package",
"pages": [
"pages/index/index",
"pages/detail/detail"
],
"independent": true
}
]
}
独立分包内的页面和组件可以被主包和其他分包引用。
分包预下载是指在小程序启动时,提前加载分包的部分代码和资源,加速分包的加载速度。
在 app.json
中的 subpackages
中使用 "preloadRule"
配置预下载规则:
{
"subpackages": [
{
"root": "subpackage1",
"pages": [
"pages/subpage1/index"
],
"preloadRule": {
"pages/subpage1/index": {
"network": "all",
"packages": ["subpackage1"]
}
}
}
]
}