目录
组件生命周期
组件引用
父组件给子组件传值
子组件给父组件传值
observers 数据监听
注意事项
组件生命周期
在介绍组件属性时,先介绍下组件的生命周期,可用的全部生命周期如下表所示:
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
created | 无 | 在组件实例刚刚被创建时执行 | 1.6.3 |
attached | 无 | 在组件实例进入页面节点树时执行 | 1.6.3 |
ready | 无 | 在组件在视图层布局完成后执行 | 1.6.3 |
moved | 无 | 在组件实例被移动到节点树另一个位置时执行 | 1.6.3 |
detached | 无 | 在组件实例被从页面节点树移除时执行 | 1.6.3 |
error | Object Error |
每当组件方法抛出错误时执行 | 2.4.1 |
关于lifetimes
:自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes
字段内进行声明(这是推荐的方式,其优先级最高)。
组件所在页的生命周期:
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
show | 无 | 组件所在的页面被展示时执行 | 2.2.3 |
hide | 无 | 组件所在的页面被隐藏时执行 | 2.2.3 |
resize | Object Size |
组件所在的页面尺寸变化时执行 | 2.4.0 |
注意:自定义 tabBar 的 pageLifetime 不会触发。
***ponent({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
关于 组件生命周期 详见官方文档
组件引用
准备页面:组件header 与 页面index
1、创建组件文件
右键 > 新建文件夹***ponents > 新建文件夹header (如果没有那么多组件可以省略,如果组件多的话最好文件夹分开) > 右键 新建***ponent (这里是global-header )
global-header.wxml内容
<view class="header">
<input type="text" placeholder="请输入内容"></input>
<view bindtap="confirmBtn" class="btn">确定</view>
</view>
2、index页面引入组件
pages目录下 index.json
{
"using***ponents": {
"header":"../../***ponents/header/global-header"
}
}
解释:
using***ponents: { "组件名": "组件所在路径" }
pages目录下 index.wxml
<header></header>
解释:
<组件名></组件名> 这个名字就是对应刚刚在 index.json 里起的名字
到此组件的引用就实现了,组件header的内容就引入到index里了
关于组件properties、attached、observers、methods 的解释说明, (global-header.js)
***ponent({
/**
* properties类似vue组件里的 props
* 组件的对外属性,用来接收外界传到组件中的数据
*/
properties: {//倾向于存储外界传递到组件中的数据
/**
name:{// 属性名
type:类型,//可选值为: Number,String、Boolean、Object、Array、null(表示不限制类型)
value:值 ,
},
*/
// 如 用户信息 userInfo 对象类型,默认是空对象
userInfo: { // 属性名
type: Object, // 属性类型
value:{},// 属性默认值
},
// 如 样例 demo 字符串类型,默认值'测试demo'
demo: { // 属性名
type: string, // 属性类型
value:'测试demo',// 属性默认值
},
},
// 组件的初始数据
data:{},//倾向于存储组件的私有数据
lifetimes: {},
attached: function () {},
//数据监听器 监听和响应任何属性和数据的变化,类似vue中watch
observers: { },
// 组件的方法列表,定义组件的事件处理函数
methods: {
//如 增加的方法
add(){console.log('增加')},
//如 删除的方法
del(){console.log('删除')}
}
})
关于 组件 ***ponent 属性方法 等详细介绍见官方文档
组件传值
父组件给子组件传值
父组件(页面index)给子组件(组件header )传值
1、在组件global-header.js中定义接收值的属性并设置类型以及初始值
/**
* 组件的属性列表
* 在组件属性列表里定义 要接收值的 属性:valueText
* 默认值为空,字符串类型,即input的value值
*/
properties: {
valueText:{
type:String,
value:''
}
},
2、global-header.wxml 中添加标签
<view class="header">
<input type="text" value="{{valueText}}" placeholder="请输入内容"></input>
<view bindtap="confirmBtn" class="btn">确定</view>
</view>
3、父组件,也就是index文件下,设置值并传给global-header
valueText 是 global-header中定义接收的属性名
value 是 index 中设置的值
<!-- index.wxml -->
<header valueText="{{value}}"></header>
// index.js
Page({
data: {
value:'index页面传给input的value值' // 从接口获取、或者自定义的 要传给 global-header的值
},
})
到此 父组件的值就传给了子组件,运行如下:
子组件给父组件传值
子组件给父组件传值要 使用 this.triggerEvent() 方法 ,该方法接收 3 个参数
//this.triggerEvent('自定义方法名', 传到组件外的数据 , 是否冒泡选项 )
this.triggerEvent('confirmBtn', myEventDetail, myEventOption)
第三个 myEventOption 是否冒泡的参数 又分 3 个选项,即下表
触发事件的选项包括:
选项名 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
bubbles | Boolean | 否 | false | 事件是否冒泡 |
***posed | Boolean | 否 | false | 事件是否可以穿越组件边界,为 false 时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部 |
capturePhase | Boolean | 否 | false | 事件是否拥有捕获阶段 |
子组件给父组件传 例:
当点击按钮 “确定” 的时候,给父组件 传新的 valueText 值
<!-- 子组件页面 global-header.wxml -->
<view class="header">
<input type="text" value="{{valueText}}" placeholder="请输入内容"></input>
<view bindtap="confirmBtn" class="btn">确定</view>
</view>
// 子组件 global-header.js
***ponent({
/**
* 组件的属性列表
*/
properties: {
valueText:String, //输入框内容
},
/**
* 组件的方法列表
*/
methods: {
//确定按钮 给父组件index 传值
confirmBtn(e){
// this.triggerEvent('传递给父组件的自定义事件名称 newValue',传给父组件的数据 valueText)
this.triggerEvent('newValue',{valueText:'子组件更改了value'})
},
},
})
父组件 index 接收传过来的值
父组件监听事件 bindnewValue = "newValue" 等同与 bind:newValue="newValue"
bind的是子组件自定义的方法名字newValue ,父组件方法名字 newValue2(这里为了区分写了newValue2)
<!-- index.wxml -->
<header valueText="{{value}}" bindnewValue="newValue2"></header>
// 父组件 index.js
Page({
data: {
value:'value值'
},
onLoad() {},
newValue2(e){
console.log('e:',e)
console.log('e.detail:',e.detail)
},
})
到此子组件传值,父组件接收完毕,运行如下:
关于 组件通信 与 事件 详见官方文档
observers 数据监听
类似 vue 中的 watch 功能,小程序基础库版本 2.6.1 开始支持
组件内global-header.js 监听
// global-header.js
***ponent({
/**
* 组件的属性列表
*/
properties: {
valueText:String, //输入框内容
},
/**
* 组件的方法列表
*/
methods: {
confirmBtn(e){
console.log('确定')
this.triggerEvent('newValue',{valueText:'子组件更改了value'})
},
},
observers:{
//监听valueText 值变化
// '字段valueText'(字段valueText的新值) {
// console.log(字段valueText的新值)
// do something
// }
'valueText'(newVal) {
console.log(newVal)
}
}
})
也可以同时监听多个
observers:{
//字段 A 和 B
// 'A,B'(A_val, B_val) {
// console.log(A_val, B_val)
// do something
// }
'A,B'(newA,newB) {
console.log(newA,newB)
}
}
父组件内新增一个按钮以便触发再次改变value 值
<!-- index.wxml -->
<header valueText="{{value}}" bindnewValue="newValue2"></header>
<view bindtap="changeVal">点击再次改变value值</view>
// index.js
Page({
data: {
value:'value值'
},
onLoad() {},
newValue2(e){
console.log('e:',e)
console.log('e.detail:',e.detail)
},
//触发按钮 在一次改变 传给 子组件的valueText的值
changeVal(e){
this.setData({
value:'再次改变value值'
})
},
})
到此observers监听数据变化已完毕,运行如下
一次 setData 最多触发每个监听器一次。同时,监听器可以监听子数据字段
注意事项
- 数据监听器监听的是 setData 涉及到的数据字段,即使这些数据字段的值没有发生变化,数据监听器依然会被触发。
- 如果在数据监听器函数中使用 setData 设置本身监听的数据字段,可能会导致死循环,需要特别留意。
- 数据监听器和属性的 observer 相比,数据监听器更强大且通常具有更好的性能。
关于 observer 数据监听 详见官方文档