> 文章列表 > 【微信小程序】生命周期,插槽和组件间通信

【微信小程序】生命周期,插槽和组件间通信

【微信小程序】生命周期,插槽和组件间通信

在这里插入图片描述

一、组件生命周期

1.1 组件全部的生命周期函数

小程序组件可用的全部生命周期如下表所示

生命周期函数 参数 描述说明
created 在组件实例刚刚被创建时执行
attached 在组件实例进入页面节点树时执行
ready 在组件在视图层布局完成后执行
moved 在组件实例被移动到节点树另一个位置时执行
detached 在组件实例被从页面节点树移除时执行
error Object Error 每当组件方法抛出错误时执行

1.2 组件主要的生命周期函数

在小程序组件中,最重要的生命周期函数有 3 个,分别是 created 、 attached 、 detached 。它们各自的特点如下:

  1. 组件实例 刚被创建 好的时候,created 生命周期函数会被触发 此时还不能调用 setData通常在这个生命周期函数中,只应该用于给组件的 this 添加一些自定义的属性字段

  2. 在组件 完全初始化完毕、进入页面节点树后 , attached 生命周期函数会被触发此时, this.data 已被初始化完毕这个生命周期很有用,绝大多数初始化的工作可以在这个时机进行(例如发请求获取初始数据)

  3. 在组件 离开页面节点树后 , detached 生命周期函数会被触发退出一个页面时,会触发页面内每个自定义组件的 detached 生命周期函数此时适合做一些清理性质的工作

/**
* 组件的初始数据
*/
data: {
_rgb:{ // rgb 的颜色值对象
r:0,
g:0,
b:
},
fullColor: '0, 0, 0' //根据rgb对象的三个属性,动态计算fullColor 的值
},
})

生命周期函数 参数 描述
show 无 组件所在的页面被展示时执行
hide 无 组件所在的页面被隐藏时执行
resize Object Size 组件所在的页面尺寸变化时执行

1.3 lifetimes 节点

在小程序组件中,生命周期函数可以直接定义在 Component 构造器的第一级参数中,可以在 lifetimes字段内进行声明( 这是推荐的方式,其优先级最高 )。示例代码如下:

二、组件所在页面的生命周期

2.1 什么是组件所在页面的生命周期

有时, 自定义组件的行为依赖于页面状态的变化 ,此时就需要用到 组件所在页面的生命周期 。例如:每 当触发页面的 show 生命周期函数的时候,我们希望能够重新生成一个随机的 RGB 颜色值。在自定义组件中,组件所在页面的生命周期函数有如下 3 个,分别是:

// components/test3/test3.js
Component({
//旧式的定义方式
created() {
console.log('created'); //在组建实例进入页面节点树时执行
},
attached(){
console.log('attached'); //在组件实例被从页面节点树移除时执行
},
// 推荐用法
lifetimes:{
created() {
console.log('created~'); //在组建实例进入页面节点树时执行
},
attached(){
console.log('attached~');//在组件实例被从页面节点树移除时执行
},
}
})

2.2 pageLifetimes 节点

组件所在页面的生命周期函数,需要定义在 pageLifetimes 节点中,示例代码如下

2.3 生成随机的 RGB 颜色值

// components/test3/test3.js
Component({
pageLifetimes:{
show(){
console.log('show');
},
hide(){
console.log('hide');
},
resize(){
console.log('resize');
}
}})
// components/test3/test3.js
Component({
/**
* 组件的方法列表
*/
methods: {
changeR(){ //修改 rgb 对象上 r属性的值
this.setData({
'_rgb.r':this.data._rgb.r + 5 > 255? 255 : this.data._rgb.r
+ 5

三、插槽

3.1 什么是插槽

在自定义组件的 wxml 结构中,可以提供一个 节点(插槽),用于 承载组件使用者提供的 wxml结构。

changeG(){ // 修改rgb对象上r属性的值
this.setData({
'_rgb.g':this.data._rgb.g + 5 >255 ?255 :this.data._rgb.g +
})
},
changeB(){//修改 rgb对象上b属性的值
this.setData({
'_rgb.b':this.data._rgb.b + 5 > 255? 255 :this.data._rgb.b
+
})
},
_randomColor() {
this.setData({
_rgb:{
r: Math.floor(Math.random() * 256),
g: Math.floor(Math.random() * 256),
b: Math.floor(Math.random() * 256)
}
})
}
},
pageLifetimes:{
show(){
console.log('show');
this._randomColor()
}
}
})

3.2 单个插槽

在小程序中,默认每个自定义组件中只允许使用一个 进行占位,这种个数上的限制叫做单个插槽。

在components 中新建一个test4文件夹 在文件中新建component

在app.json usingComponents中 添加组件目录

"usingComponents": {
"my-test1":"/components/test/test",
"my-test2":"/components/test2/test2",
"my-test3":"/components/test3/test3",
"my-test4":"/components/test4/test4"
},

在组件.wxml中定义结构

<!--components/test4/test4.wxml-->
<view>
<view>
这里是组件的内部结构
</view>
<slot></slot>
</view>

在页面的.wxml定义结构:

<!--pages/home/home.wxml-->
<my-test4>
<view>
这是通过插槽填充的内容
</view></my-test4>

3.3 定义多个插槽

可以在组件的 .wxml 中使用多个 标签,以不同的 name 来区分不同的插槽。在组件.wxml中 加上一个slot标签 为每个slot标签定义name属性值

// components/test4/test4.js
Component({
options: {
multipleSlots: true //在组件定义时选型中启用多slot支持
},
properties: {/* ... */},
data: {/* ... */},
methods: {/* ... */ }
})
<!--components/test4/test4.wxml-->
<view>
<slot name="before"></slot>
<view> 这里是组件的内部结构 </view>
<slot name="after"></slot>
</view>

四、父子组件之间的通信

4.1 父子组件之间通信的 3 种方式

1. 属性绑定

用于父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容的数据

2. 事件绑定

用于子组件向父组件传递数据,可以传递任意数据

3. 获取组件实例

父组件还可以通过 this.selectComponent() 获取子组件实例对象可以直接访问子组件的任意数据和方法

4.2 属性绑定

属性绑定用于实现父向子传值,而且只能传递普通类型的数据,无法将方法传递给子组件
在home.js中定义数据

<my-test4>
<!-- 这部分内容将被放置在组件 <slot name="after">的位置上 -->
<view slot="after">这是通过插槽填充的内容</view>
<!-- 这部分内容将被放置在组件 <slot name="before">的位置上 -->
<view slot="before">~~~~~~~</view>
</my-test4>
// 父组件的data节点
data: {
count:0
}
在home.js中定义结构

在components 中新建一个test5文件夹 在文件中新建component

在app.json usingComponents中 添加组件目录:

在home首页中使用一下这个组件

子组件在 properties 节点中声明对应的属性,并使用实现子组件按钮自增加一的效果

// 父组件的.wxml结构
<my-test3 count="{{count}}"> </my-test3>
<view>-----</view>
<view>父组件中,count值为:{{count}}</view>
"usingComponents": {
"my-test1":"/components/test/test",
"my-test2":"/components/test2/test2",
"my-test3":"/components/test3/test3",
"my-test4":"/components/test4/test4",
"my-test5":"/components/test5/test5"
},
<my-test5 count="{{count}}"></my-test5>
<view>~~~~~~~~~~~</view>
<view>父组件中,count值是:{{count}}</view>
// components/test5/test5.js
Component({
/**
* 组件的属性列表
*/
properties: {
count:Number

4.3 事件绑定

事件绑定 用于实现子 向父传值 ,可以传递任何类型的数据。使用步骤如下:

步骤 1 :在父组件的 js 中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件。

  1. 在 父组件 的 js 中,定义一个函数,这个函数 即将 通过自定义事件的形式,传递给子组件

  2. 在 父组件 的 wxml 中,通过自定义事件的形式,将步骤 1 中定义的函数引用,传递给子组件

  3. 在子组件的 js 中,通过调用 this.triggerEvent (‘自定义事件名称’, { /* 参数对象 */ }) ,将数据发送到父组件

  4. 在 父组件 的 js 中,通过 e.detail 获取到子组件传递过来的数据

步骤 2 :在 父组件 的 wxml 中(home.wxml),通过 自定义事件 的形式,将步骤 1 中定义的函数引用,

传递给子组件。

使用bind:自定义事件名称 (推荐:结构清晰)

或在bind后面直接写上自定义事件名称

步骤 3 :在子组件的 js 中,通过调用 this.triggerEvent(‘自定义事件名称’, { /* 参数对象 */ }) ,将数据发子组件的.wxml结构(test5.wxml)

子组件的js代码

//在父组件中定义sysncCount方法
// 将来,这个方法会被传递给子组件,供子组件进行调用
Page({
/**
* 页面的初始数据
*/
data: {
count:0
},
sysncCount(){
console.log('sysncCount');
},
 <my-test5 count="{{count}}" bind:sync="sysncCount"></my-test5>
<view>子组件中,count值是:{{count}}</view>
<button type="primary" bindtap="addCount">+1</button>
// components/test5/test5.js
Component({
methods: {
addCount(){
this.setData({
count:this.properties.count + 1
})
// 触发自定义事件,将数值同步给父组件
this.triggerEvent('sync',{value:this.properties.count})
}
}
})

在父组件的 js 中,通过 e.detail 获取到子组件传递过来的数据。

4.4 获取组件实例

可在父组件里调用 this.selectComponent(“id或class选择器”) ,获取子组件的实例对象,从而直接访问子组件的任意数据和方法。调用时需要传入一个选择器,例如 this.selectComponent(“.my- component”)。
home.wxml定义结构

sysncCount(e){
// console.log('sysncCount');
// console.log(e);
// console.log(e.detail.value);
this.setData({
count: e.detail.value
})
},
<my-test5 count="{{count}}" bind:sync="sysncCount" class="customA" id='cA'>
</my-test5>
<view>~~~~~~~~~~~</view>
<view>父组件中,count值是:{{count}}</view>
<button bindtap="getChild">获取子组件的实例对象</button>
// pages/home/home.js
Page({
/**
* 页面的初始数据
*/
data: {
count:0
},
sysncCount(e){
// console.log('sysncCount');
// console.log(e);
// console.log(e.detail.value);
this.setData({
count: e.detail.value
})
},
getChild(){
//切记不能传递标签选择器否自返回的是null
const child = this.selectComponent('.customA')
// console.log(child);
// 调用子组件的 setData方法
// child.setData({
// count:child.properties.count +1 //注意此处只能用child不能用this
// })
child.addCount()//调用子组件的addCount方法
},
})