官方文档:自定义组件
一、小程序组件 – 创建与引用
1. 组件的创建
- 在项目的根目录中,鼠标右键,创建 components 文件夹 --> test
- 在新建的 components -> test 文件夹上,鼠标右键,点击“新建 Component”
- 为新建的组件命名之后,会自动生成组件对应的 4 个文件,后缀名分别为
.js
,.json
,.wxml
和.wxss
注意:应当尽量将不同的组件,存放到单独的文件夹中,从而保证清晰的目录结构
2. 组件的引用
- 在需要引用组件的页面中,找到页面的
.json
配置文件,新增usingComponents
节点 - 在
usingComponents
中,通过键值对的形式,注册组件;键为注册的组件名称,值为组件的相对路径 - 在页面的
.wxml
文件中,把注册的组件名称,以标签形式在页面上使用,即可把组件展示到页面上
<!--components/test/test.wxml-->
<text>components/test/test.wxml</text>
// tabContact.json
{
"usingComponents": {
"custom-test":"../../components/test/test"
}
}
<!--pages/tabContact/tabContact.wxml-->
<text>pages/tabContact/tabContact.wxml</text>
<view><custom-test></custom-test></view>
<!--页面解析后的结果-->
<page>
<text>
pages/tabContact/tabContact.wxml
</text>
<view>
<custom-test is="components/test/test">
#shadow-root
<text>
components/test/test.wxml
</text>
</custom-test>
</view>
</page>
注册组件名称时,建议把组件名称使用中横线进行连接,例如 vant-button 或 custom-button
二、小程序组件 – 组件的样式
- 组件对应
wxss
文件的样式,只对组件wxml
内的节点生效。编写组件样式时,需要注意以下几点: - 组件和引用组件的页面不能使用id选择器(#a)、属性选择器([a])和标签名选择器,
请改用 class选择器
。 - 组件和引用组件的页面中使用后代选择器(.a .b)
在一些极端情况下会有非预期的表现
,如遇,请避免使用。 子元素选择器(.a>.b),只能用于 view 组件与其子节点之间
,用于其他组件可能导致非预期的情况。- 继承样式,如
font
、color
,会从组件外继承到组件内。 - 除继承样式外,
app.wxss
中的样式、组件所在页面的样式对自定义组件无效。
注意:以上语法不推荐死记硬背,建议都使用 class 选择器
三、小程序组件 – 数据与方法
官方文档:组件详细的参数含义和使用
1. 使用 data 定义组件的私有数据
-
小程序组件中的
data
与小程序页面中的data
用法一致,区别是:- 页面的
data
定义在Page()
函数中 - 组件的
data
定义在Component()
函数中
- 页面的
-
在组件的
.js
文件中:- 如果要访问
data
中的数据,直接使用this.data.数据名称
即可 - 如果要为
data
中的数据重新赋值,调用this.setData({ 数据名称: 新值 })
即可
- 如果要访问
-
在组件的 .wxml 文件中
- 如果要渲染 data 中的数据,直接使用 {{ 数据名称 }} 即可
/**
* 组件的初始数据
*/
data: {
num:1
},
2. 使用 methods 定义组件的事件处理函数
官方文档:组件间通信与事件 详细文档
- 和页面不同,组件的事件处理函数,必须定义在 methods 节点中
/**
* 组件的方法列表
*/
methods: {
handle: function () {
console.log('组件的方法要定义在 methods 中')
this.setData({
num: this.data.num + 1
})
console.log(this.data.num)
}
}
3. 组件的 properties
3.1 properties 简介
组件的对外属性,用来接收外界传递到组件中的数据。 类似于
Vue
中的props
,小程序组件中的 properties,是组件的对外属性,用来接收外界传递到组件中的数据。
在小程序中,组件的 properties 和 data 的用法类似,它们都是可读可写的
data
更倾向于存储组件的私有数据
properties
更倾向于存储外界传递到组件中的数据
3.2 声明 properties 的两种方式
// 组件的js
Component({
/**
* 组件的属性列表
*/
properties: {
// 完整的定义方式
propA: { // 属性名
type: String, // 属性类型
value: '' // 属性默认值
},
propB: String // 简化的定义方式
}
})
注意:type 的可选值为 Number,String、Boolean、Object、Array、null(表示不限制类型)
3.3 为组件传递 properties 的值
可以使用数据绑定的形式,用于父组件向子组件的属性传递动态数据
<!-- 引用组件的页面模板 -->
<second-com prop-a="{{ priceData }}"></second-com>
注意:
- 在定义 properties 时,属性名采用
驼峰写法
(propertyName); - 在 wxml 中,指定属性值时,则对应使用
连字符写法
(property-name=“attr value”), - 应用于数据绑定时,采用
驼峰写法
(attr="{{propertyName}}")。
实例代码:
//组件的js
properties: {
propPrice: {
type: Number,
value: 1
}
},
<!-- 引用组件的页面 -->
<!--属性名为propPrice的驼峰命名属性在wxml页面采用 prop-price连字符的形式-->
<!--priceData 为当前页面在data中设置传给组件的动态值 ,通过改变pricData的值就可以改变组件页面propPrice的值-->
<second-com prop-price="{{ priceData }}"></second-com>
<!-- 组件页面 -->
<!-- propPrice为设置在properties中的属性-->
<view>{{ propPrice }}</view>
3.4 组件内修改 properties
properties 的值是可读可写的,可以通过
setData
修改properties
中任何属性的值,最好不要使用这种,用父属性的改变来操作子组件值的变化,这样更符合规范
- 案例代码
methods: {
handle: function () {
this.setData({
propPrice: this.properties.propPrice + 1
})
console.log(this.properties.propPrice)
}
}
四、小程序组件 – 数据监听器
官方文档:数据监听详细文档
数据监听器可以用于
监听
和响应
任何属性和数据字段的变化,从而执行特定的操作。作用类似于vue
中的watch
。
数据监听器从小程序基础库版本2.6.1
开始支持。
1. 基本使用方法
//组件的js
observers: {
// 当data,properties中的属性进行setData来改变数据时就会被监听到,即使值没有发生变化
// propPrice为properties中的属性,num为data中的属性
// newPropPrice,newNum是前面监听数据的形参,个数与前面的一一对应
'propPrice, num': function (newPropPrice, newNum) {
console.log(newPropPrice)
console.log(newNum)
}
},
2. 监听子数据字段语法
- 案例代码
// 监控某个子数据的代码
Component({
observers: {
'some.subfield': function (subfield) {
// 使用 setData 设置 this.data.some.subfield 时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
},
'arr[12]': function (arr12) {
// 使用 setData 设置 this.data.arr[12] 时触发
// (除此以外,使用 setData 设置 this.data.arr 也会触发)
}
}
})
// 使用通配符 ** 监听所有子数据字段的变化
Component({
observers: {
'some.field.**': function (field) {
// 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
field === this.data.some.field
}
}
})
五、组件的生命周期
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。
1. 组件的主要生命周期
-
最重要的生命周期是
created
,attached
,detached
,包含一个组件实例生命流程的最主要时间点。- 组件实例刚刚被创建好时,
created
生命周期被触发。此时还不能调用setData
。 通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段。 - 在组件完全初始化完毕、进入页面节点树后,
attached
生命周期被触发。此时,this.data
已被初始化完毕。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。
- 在组件离开页面节点树后,
detached
生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则detached
会被触发。
- 组件实例刚刚被创建好时,
-
其他: 组件生命周期详解
2. 定义生命周期函数
lifetimes: {
attached() {}, // 在组件实例进入页面节点树时执行
detached() {}, // 在组件实例被从页面节点树移除时执行
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached() {}, // 在组件实例进入页面节点树时执行
detached() {}, // 在组件实例被从页面节点树移除时执行
// ...
})
3. 组件所在页面的生命周期
有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes
定义段中定义。其中可用的生命周期包括:
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
show | 无 | 组件所在页面被展示时执行 | 2.2.3 |
hide | 无 | 组件所在页面被隐藏时执行 | 2.2.3 |
resize | Object Size | 组件所在页面尺寸变化时执行 | 2.4.0 |
Component({
pageLifetimes: {
show() { // 页面被展示
},
hide() { // 页面被隐藏
},
resize(size) { // 页面尺寸变化
}
}
})
六、组件插槽
1. 匿名插槽
在
组件
的wxml
中可以包含slot
节点,用于承载组件使用者
提供的wxml
结构。
- 默认情况下,一个组件的
wxml
中只能有一个slot
。需要使用多slot
时,可以在组件js
中声明启用。 - 注意:小程序中目前只有匿名插槽和具名插槽,暂不支持作用域插槽。
- 案例代码
<!-- 组件模板-->
<view>
<view>我是组件</view>
<slot></slot>
</view>
<!-- 引用组件的页面模板-->
<second-com>
<!--这个view里的内容会被插入slot这个匿名插槽里-->
<view>你好,我是引用组件</view>
</second-com>
2. 具名插槽
1、在组件中,需要使用多 slot
时,可以在组件 js
中声明启用。
//对组件js的设置
Component({
options: {
multipleSlots: true
},
})
2、在组件的 wxml
中使用多个 slot
标签,以不同的name
来区分不同的插槽
<view>
<view>我是组件</view>
<slot name="name"></slot>
<slot name="age"></slot>
</view>
3、 使用多个插槽
<!--引用组件的页面模板-->
<second-com prop-price="{{ priceData }}">
<!--不同slot值的view里面的内容会插入到组件wxml页面里相同的name值的slot里-->
<view slot="name">你好,这是 name 插槽 </view>
<view slot="age">你好,这是 age 插槽</view>
</second-com>
- 当开启多插槽模式时(设置属性为true),引用组件里如果有引入未定义的具名插槽将不会在页面显示
- 当关闭多插槽模式时(设置属性为false),引用带名字的插槽就没有了意义,会被当做匿名插槽来进行渲染
七、组件间的通信
官方文档:组件间通信与事件
1. 组件之间的三种基本通信方式
WXML
数据绑定:用于父组件向子组件
的指定属性传递数据,仅能设置JSON
兼容数据,即利用properties
,这个本文上面有介绍- 事件:用于
子组件向父组件
传递数据,可以传递任意数据。 - 父组件通过
this.selectComponent
方法获取子组件实例对象
,便可以直接访问组件的任意数据和方法。
2. 通过事件监听实现子向父传值
事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件。
什么是自定义事件呢,你可以简单的理解为:在触发子组件的一些事件的时候,同时也能触发父组件对应的事件并对父组件中的某些数据进行修改的事件就是自定义事件.
2.1 在父组件
的 js
中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
getNum(){
console.log('开始获取子组件传递的值')
}
2.2 在父组件
的 wxml
中,通过自定义事件的形式,将步骤一中定义的函数引用,传递给子组件
<!--bind:后面的myEvent为自定义事件名,要与this.triggerEvent中的事件名保持一致,getNum为父组件定义的函数-->
<view>
<custom-test bind:myEvent="getNum"></custom-test>
<!-- 或者可以写成 -->
<!--<custom-test bindmyEvent="getNum"></custom-test>-->
</view>
2.3 在子组件
的 js
中,通过调用 this.triggerEvent('自定义事件名称', { /* 参数对象 */ })
,将数据发送到父组件
<!--子组件页面,设置按钮进行事件的触发-->
<view>=====下面是通过自定义事件传值到父级====</view>
<button bindtap="sendValue" type="primary">自定义事件传值</button>
//子组件的js
/**
* 组件的初始数据
*/
data: {
num:1
},
/**
* 组件的方法列表
*/
methods: {
sendValue() {
this.triggerEvent('myEvent',{num:this.data.num})
}
}
2.4 在父组件
的 js
中,通过 e.detail
获取到子组件传递过来的数据
getNum(e) {
console.log('开始获取子组件的num值')
console.log(e)
},
3.this.selectComponent
使用
父组件的
.js
文件中,可以调用this.selectComponent(string)
函数并指定id
或class
选择器, 获取子组件对象调用
,可以返回指定组件的实例对象
<!--引用组件的页面-->
<custom-test class='first' id="second"></custom-test>
<!--触发事件按钮-->
<button bindtap="testSltCom" type="primary">测试this.selectComponent使用</button>
// 引用组件页面的js
testSltCom() {
console.log("打印class来调用")
console.log(this.selectComponent ('.first'))
console.log("-----------------------------")
console.log("打印id来调用")
console.log(this.selectComponent('#second'))
},