开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。自定义组件在使用时与基础组件非常相似。
类似于页面,一个自定义组件由 json wxml wxss js 4个文件组成。要编写一个自定义组件,首先需要在 json 文件中进行自定义组件声明(将 component 字段设为 true 可将这一组文件设为自定义组件):
{
"component": true
}
同时,还要在 wxml 文件中编写组件模板,在 wxss 文件中加入组件样式,它们的写法与页面的写法类似。
<view class="inner">
{{innerText}}
view>
<slot>slot>
/* 这里的样式只应用于这个自定义组件 */
.inner {
color: red;
}
在自定义组件的 js 文件中,需要使用 Component() 来注册组件,并提供组件的属性定义、内部数据和自定义方法。
组件的属性值和内部数据将被用于组件 wxml 的渲染,其中,属性值是可由组件外部传入的。
Component({
properties: {
// 这里定义了 innerText 属性,属性值可以在组件使用时指定
innerText: {
type: String,
value: 'default value',
}
},
data: {
// 这里是一些组件内部数据
someData: {}
},
methods: {
// 这里是一个自定义方法
customMethod: function(){}
}
})
使用已注册的自定义组件前,首先要在页面的 json 文件中进行引用声明。此时需要提供每个自定义组件的标签名和对应的自定义组件文件路径:
{
"usingComponents": {
"component-tag-name": "path/to/the/custom/component"
}
}
这样,在页面的 wxml 中就可以像使用基础组件一样使用自定义组件。节点名即自定义组件的标签名,节点属性即传递给组件的属性值。
<view>
<component-tag-name inner-text="Some text">component-tag-name>
view>
自定义组件的 wxml 节点结构在与数据结合之后,将被插入到引用位置内。
一些需要注意的细节:
组件模板的写法与页面模板相同。组件模板与组件数据结合后生成的节点树,将被插入到组件的引用位置上。
在组件模板中可以提供一个 节点,用于承载组件引用时提供的子节点。
<view class="wrapper">
<view>这里是组件的内部节点view>
<slot>slot>
view>
<view>
<component-tag-name>
<view>这里是插入到组件 slot 中的内容view>
component-tag-name>
view>
注意,在模板中引用到的自定义组件及其对应的节点名需要在 json 文件中显式定义,否则会被当作一个无意义的节点。除此以外,节点名也可以被声明为抽象节点。
组件对应 wxss 文件的样式,只对组件 wxml 内的节点生效。编写组件样式时,需要注意以下几点:
#a { } /* 在组件中不能使用 */
[a] { } /* 在组件中不能使用 */
button { } /* 在组件中不能使用 */
.a > .b { } /* 除非 .a 是 view 组件节点,否则不一定会生效 */
默认情况下,自定义组件的样式只受到自定义组件 wxss 的影响。除非以下两种情况:
Component({
// 样式隔离:apply-shared 父影响子,shared父子相互影响, isolated相互隔离
options: {
styleIsolation: 'isolated'
}
})
styleIsolation 选项从基础库版本 2.6.5 开始支持。它支持以下取值:
有时,组件希望接受外部传入的样式类。此时可以在 Component 中用 externalClasses 定义段定义若干个外部样式类。
这个特性可以用于实现类似于 view 组件的 hover-class 属性:页面可以提供一个样式类,赋予 view 的 hover-class ,这个样式类本身写在页面中而非 view 组件的实现中。
/* 组件 custom-component.js */
Component({
externalClasses: ['my-class']
})
<custom-component class="my-class">
这段文本的颜色由组件外的 class 决定
custom-component>
这样,组件的使用者可以指定这个样式类对应的 class ,就像使用普通属性一样。
<custom-component my-class="red-text" />
<custom-component my-class="large-text" />
<custom-component my-class="red-text large-text" />
.red-text {
color: red;
}
.large-text {
font-size: 1.5em;
}
<cell>
<text>插槽内容text>
cell>
<view><slot>slot>view>
<cell>
<text slot="pre"> text>
<text slot="next">text>
cell>
options:{ multipleSlots:true}
<view>
<slot name="pre">slot>
<slot name="next">slot>
view>
父传子
property
子传参父
triggerEvent
Component 构造器可用于定义组件,调用 Component 构造器时可以指定组件的属性、数据、方法等。
Component({
behaviors: [],
properties: {
myProperty: { // 属性名
type: String,
value: ''
},
myProperty2: String // 简化的定义方式
},
data: {}, // 私有数据,可用于模板渲染
lifetimes: {
// 生命周期函数,可以为函数,或一个在 methods 段中定义的方法名
attached: function () { },
moved: function () { },
detached: function () { },
},
// 生命周期函数,可以为函数,或一个在 methods 段中定义的方法名
attached: function () { }, // 此处 attached 的声明会被 lifetimes 字段中的声明覆盖
ready: function() { },
pageLifetimes: {
// 组件所在页面的生命周期函数
show: function () { },
hide: function () { },
resize: function () { },
},
methods: {
onMyButtonTap: function(){
this.setData({
// 更新属性和数据的方法与更新页面数据的方法类似
})
},
// 内部方法建议以下划线开头
_myPrivateMethod: function(){
// 这里将 data.A[0].B 设为 'myPrivateData'
this.setData({
'A[0].B': 'myPrivateData'
})
},
_propertyChange: function(newVal, oldVal) {
}
}
})
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。
其中,最重要的生命周期是 created attached detached ,包含一个组件实例生命流程的最主要时间点。
生命周期方法可以直接定义在 Component 构造器的第一级参数中。
Component({
lifetimes: {
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
// ...
})
在 behaviors 中也可以编写生命周期方法,同时不会与其他 behaviors 中的同名生命周期相互覆盖。但要注意,如果一个组件多次直接或间接引用同一个 behavior ,这个 behavior 中的生命周期函数在一个执行时机内只会执行一次。
可用的全部生命周期如下: