小程序自定义组件(父子组件通信)+npm包的使用
创建自定义组件
在根目录下创建 components
文件夹 下创建自定义的组件
引用自定义组件
// 在页面的 .json 文件中,引入组件
{
"usingComponents": {
"my-test1": "/components/test1/test1"
}
}
// 在页面的 .wxml 文件中,使用组件
<my-test1></mytest1>
组件和页面的区别
-
组件中的 .json 文件中需要声明
“component”:true
属性 -
组件的 .js 文件中调用的是
Component()
函数 -
组件的事件处理函数需要定义到 methods 节点中
组件样式隔离
组件的样式不会影响组件之外的样式
注意:
-
app.wxss 定义的样式对组件样式无效
-
只有 class 选择器会有样式隔离效果,id 选择器、属性选择器、标签选择器不受样式隔离的影响
建议:在组件和引用组件的页面中建议使用 class 选择器,
不要使用 id、属性、标签选择器!
修改组件的样式隔离选项
通过 styleIsolation
修改组件的样式隔离选项
// 在组件的 .js 文件中新增如下配置
Component({
options:{
styleIsolation: 'isolated'
}
})
// 或在组件的 .json 文件中新增配置如下
{
"styleIsolation": "isolated"
}
自定义组件的方法
自定义方法建议以 _ 开头
properties 属性
是组件的对外属性,用来接收外界传递到组件中的数据。
Component({
// 属性定义
properties: {
max: { // 完整定义属性的方式【当需要指定属性默认值时,建议使用此方式】
type: Number, // 属性值的数据类型
value: 10 // 属性默认值
},
max: Number // 简化定义属性的方式【不需要指定属性默认值时,可以使用简化方式】
}
})
<my-test1 max="10"></my-test1>
data 和 properties 的区别
都是可读可写的。
-
data
更倾向于存储组件的私有数据 -
properties
更倾向于存储外界传递到组件中的数据
使用 setData
修改 properties
的值
Component({
properties: { max: Number }, // 定义属性
methods: {
addCount(){
this.setData({ max: this.properties.max + 1 }) // 使用 setData 修改属性的值
}
}
})
数据监听器
类似于 vue 中的数据监听器
Component({
observers: {
'字段A, 字段B': function(字段A的新值, 字段B的新值){
// do something
}
}
})
Component({
observers: {
'rgb.**': function(obj){
this.setData({
fullColor: `${obj.r}, ${obj.g}, ${obj.b}`
})
}
}
})
纯数据字段
指定 pureDataPattern
为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段。
Component({
options: {
// 指定所有 _ 开头的数据字段为纯数据字段
pureDataPattern: /^_/
},
data: {
a: true, // 普通字段
_b: true, // 纯数据字段
}
}
组件的生命周期
created 、 attached 、ready 、moved 、detached 、 error
created :不能调用 setData;通常在这个生命周期函数中,只用于给组件的 this 添加一些自定义的属性字段。
attached:this.data 此时已初始化完毕;初始化的工作可以在这里进行(例如发请求获取初始数据)
detached:退出一个页面时,会触发页面内每个自定义组件的 detached 生命周期函数;此时适合做一些清理性质的工作
lifetimes节点
Component({
lifetimes: {
created(){
// do something
},
attached(){
}
}
}
组件所在页面的生命周期函数
show \ hide \ resize
pageLifetimes 节点
Component({
pageLifetimes: {
show: function(){}, // 页面被展示时
hide: function(){}, // 页面被隐藏时
resize: function(){} // 页面尺寸发生变化时
}
}
自定义组件的插槽
<slot> 插槽,占位符
单个插槽
在小程序中,默认每个自定义组件中只允许使用一个 <slot> 插槽
// 组件的封装者
<view>
<view>这里是组件的内部节点</view>
// 对于不确定的内容,可以使用 插槽 占位,具体内容由组件的使用者决定
<slot></slot>
</view>
<component-tag-name>
// 这部分内容将放置在组件 插槽 的位置上
<view>这里是插入到组件slot中的内容</view>
</component-tag-name>
多个插槽
Component({
options: {
mulitipSlots: true // 在组件定义时的选项中启用多 slot 支持
},
})
// 组件的封装者
<view>
<view>这里是组件的内部节点</view>
// 对于不确定的内容,可以使用 插槽 占位,具体内容由组件的使用者决定
<slot name="before"></slot>
<slot name="after"></slot>
</view>
<component-tag-name>
// 这部分内容将放置在组件 插槽 的位置上
<view slot="before">这里是插入到组件slot中的内容</view>
<view slot="after">这里是插入到组件slot中的内容</view>
</component-tag-name>
组件通信
父子组件通信
-
属性绑定
-
用于父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容
-
-
事件绑定
-
用于子组件向父组件传递数据,可以传递任意数据
-
在父组件的 js 中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
-
在父组件的 wxml 中,通过自定义事件的形式,将👆步骤中定义的函数引用,传递给子组件
-
在子组件的 js 中,通过调用 this.triggerEvent('自定义事件名称',{/参数对象/}),将数据发送到父组件
-
在父组件的 js 中,通过 e.detail 获取到子组件传递过来的数据
-
-
-
获取组件实例
-
父组件还可以通过
this.selectComponent()
获取子组件实例对象 -
这样就可以直接访问子组件任意数据和方法
-
// 父传子 属性绑定
// 子组件在 properties 节点中声明对应的属性并使用
properties: {
count: Number
}
// 子组件的 wxml 结构
<text>子组件中,count值为:{{count}}</text>
// 子传父 事件绑定
// 父组件中定义方法
syncCount(e){
this.setData({
count: e.detail.value
})
}
<view bind:sync="syncCount"></view>
// 子组件中 调用方法
methods: {
addCount(){
// 触发自定义事件,给父组件传值
this.triggerEvent('sync', {value: this.properties.count})
}
}
// 父组件获取子组件的实例对象
// wxml 结构
<my-test class="custiom" id="cA"></my-test>
<button bindtap="getChild">获取子组件实例</button>
getChild(){ // 按钮的 tap 事件处理函数
// 切记下面参数不能传递标签选择器,'my-test',不然返回的是null
const child = this.selectComponent('.customA') // 也可以传递 id 选择器 #cA
child.setData({ count: child.proprties.count + 1 }) // 调用子组件的 setData 方法
child.addCount() // 调用子子组件的 addCount 方法
}
behaviors
用于实现组件间代码共享的特性,类似于 Vue.js 中的 "mixins
"。
behavior
可以包含一组属性、数据、声明周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中。
创建 behaviors
调用 Behavior(Object object)
方法即可创建一个共享的 behavior
实例对象,供所有的组件使用
// 调用 Behavior() 方法,创建实例对象
// 并使用 module.exports 将 behavior 实例对象共享出去
module.exports = Behavior({
// 属性节点
properties: {},
// 私有数据节点
data: { username: 'zs' },
// 事件处理函数和自定义方法节点
methods: {},
// 其他节点。。。
})
导入并使用 behavior
在组件中,使用 require()
方法导入需要的 behavior
,挂载后即可访问 behavior
中的数据或方法。
// 1.使用 require() 导入需要的自定义 behavior 模块
const myBehavior = require('../../behavior/my-behavior')
Component({
// 2.将导入的 behavior 实例对象,挂载到 behavior 数组节点中,即可生效
behaviors: [myBehavior],
// 组件的其他节点。。。
})
同名字段的覆盖和组合规则
组件和它引用的 behavior 中可以包含同名的字段,此时可以参考如下3种同名时的处理规则:
-
同名的数据字段(data)
-
同名的属性(properties)或方法(methods)
-
同名的生命周期函数
使用 npm 包
小程序对 npm 的限制
限制:
-
不支持依赖于 Node.js 内置库的包
-
不支持依赖于浏览器内置对象的包
-
不支持依赖于 C++ 插件的包
API Promise化
小程序官方提供的异步 API 都是基于回调函数实现的。容易造成回调地狱的问题,代码的可读性、维护性差。
API Promise化,指的是通过额外的配置,将官方提供的、基于回调函数的异步 API,升级改造为基于 Promise 的异步 API,从而提高代码的可读性、维护性,避免回调地狱的问题。
实现 API Promise 化主要依赖于 miniprogram-api-promise
这个第三方的 npm 包。安装步骤如下:
npm install --save miniprogram-api-promise@1.0.4
// 在小程序入口文件中(app.js),只需调用一次 promisifyAll() 方法
// 即可实现异步 API 的 Promise 化
import { promisifyAll } from 'miniprogram-api-promise'
const wxp = wx.p = {}
// promisify all wx's api
promisifyAll(wx,wxp)
调用 promise 化的 API
// 页面 .wxml 结构
<van-button bandtap="getInfo"></van-button>
// 在页面的 .js 文件中,定义对应的 tap 事件处理函数
async getInfo() {
const {data: res} = await wx.p.request({
method: 'GET',
url: 'url',
data: {data...}
})
}