ylbtech-小程序:自定义组件 |
1. 自定义组件返回顶部 |
从小程序基础库版本 1.6.3 开始,小程序支持简洁的组件化编程。html
开发者能够将页面内的功能模块抽象成自定义组件,以便在不一样的页面中重复使用;也能够将复杂的页面拆分红多个低耦合的模块,有助于代码维护。自定义组件在使用时与基础组件很是类似。node
相似于页面,一个自定义组件由 json
wxml
wxss
js
4个文件组成。要编写一个自定义组件,首先须要在 json
文件中进行自定义组件声明(将 component
字段设为 true
可这一组文件设为自定义组件):编程
{
"component": true
}
同时,还要在 wxml
文件中编写组件模版,在 wxss
文件中加入组件样式,它们的写法与页面的写法相似。具体细节和注意事项参见 组件模版和样式 。json
代码示例:小程序
<!-- 这是自定义组件的内部WXML结构 --> <view class="inner"> {{innerText}} </view> <slot></slot>
/* 这里的样式只应用于这个自定义组件 */
.inner {
color: red;
}
注意:在组件wxss中不该使用ID选择器、属性选择器和标签名选择器。api
在自定义组件的 js
文件中,须要使用 Component()
来注册组件,并提供组件的属性定义、内部数据和自定义方法。数组
组件的属性值和内部数据将被用于组件 wxml
的渲染,其中,属性值是可由组件外部传入的。更多细节参见 Component构造器 。app
代码示例:xss
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
节点结构在与数据结合以后,将被插入到引用位置内。
Tips:
usingComponents
字段)。2. 组件模版和样式返回顶部 |
相似于页面,自定义组件拥有本身的 wxml
模版和 wxss
样式。
组件模版的写法与页面模板相同。组件模版与组件数据结合后生成的节点树,将被插入到组件的引用位置上。
在组件模板中能够提供一个 <slot>
节点,用于承载组件引用时提供的子节点。
代码示例:
<!-- 组件模板 --> <view class="wrapper"> <view>这里是组件的内部节点</view> <slot></slot> </view>
<!-- 引用组件的页面模版 --> <view> <component-tag-name> <!-- 这部份内容将被放置在组件 <slot> 的位置上 --> <view>这里是插入到组件slot中的内容</view> </component-tag-name> </view>
在组件的wxml中能够包含 slot
节点,用于承载组件使用者提供的wxml结构。
默认状况下,一个组件的wxml中只能有一个slot。须要使用多slot时,能够在组件js中声明启用。
Component({
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
properties: { /* ... */ },
methods: { /* ... */ }
})
此时,能够在这个组件的wxml中使用多个slot,以不一样的 name
来区分。
<!-- 组件模板 --> <view class="wrapper"> <slot name="before"></slot> <view>这里是组件的内部细节</view> <slot name="after"></slot> </view>
使用时,用 slot
属性来将节点插入到不一样的slot上。
<!-- 引用组件的页面模版 --> <view> <component-tag-name> <!-- 这部份内容将被放置在组件 <slot name="before"> 的位置上 --> <view slot="before">这里是插入到组件slot name="before"中的内容</view> <!-- 这部份内容将被放置在组件 <slot name="after"> 的位置上 --> <view slot="after">这里是插入到组件slot name="after"中的内容</view> </component-tag-name> </view>
组件对应 wxss
文件的样式,只对组件wxml内的节点生效。编写组件样式时,须要注意如下几点:
#a
)、属性选择器([a]
)和标签名选择器,请改用class选择器。.a .b
)在一些极端状况下会有非预期的表现,如遇,请避免使用。.a>.b
)只能用于 view
组件与其子节点之间,用于其余组件可能致使非预期的状况。font
、 color
,会从组件外继承到组件内。app.wxss
中的样式、组件所在页面的的样式对自定义组件无效。#a { } /* 在组件中不能使用 */
[a] { } /* 在组件中不能使用 */
button { } /* 在组件中不能使用 */
.a > .b { } /* 除非 .a 是 view 组件节点,不然不必定会生效 */
除此之外,组件能够指定它所在节点的默认样式,使用 :host
选择器(须要 1.7.2 或更高版本的开发者工具支持)。
代码示例:
/* 组件 custom-component.wxss */
:host {
color: yellow;
}
:host(.dark) {
color: black;
}
<!-- 页面的 WXML --> <custom-component>这段文本是黄色的</custom-component> <custom-component class="dark">这段文本是黑色的</custom-component>
3. Component构造器返回顶部 |
Component构造器可用于定义组件,调用Component构造器时能够指定组件的属性、数据、方法等。
定义段 | 类型 | 是否必填 | 描述 |
---|---|---|---|
properties | Object Map | 否 | 组件的对外属性,是属性名到属性设置的映射表,属性设置中可包含三个字段, type 表示属性类型、 value 表示属性初始值、 observer 表示属性值被更改时的响应函数 |
data | Object | 否 | 组件的内部数据,和 properties 一同用于组件的模版渲染 |
methods | Object | 否 | 组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用,参见 组件事件 |
behaviors | String Array | 否 | 相似于mixins和traits的组件间代码复用机制,参见 behaviors |
created | Function | 否 | 组件生命周期函数,在组件实例进入页面节点树时执行,注意此时不能调用 setData |
attached | Function | 否 | 组件生命周期函数,在组件实例进入页面节点树时执行 |
ready | Function | 否 | 组件生命周期函数,在组件布局完成后执行,此时能够获取节点信息(使用 SelectorQuery ) |
moved | Function | 否 | 组件生命周期函数,在组件实例被移动到节点树另外一个位置时执行 |
detached | Function | 否 | 组件生命周期函数,在组件实例被从页面节点树移除时执行 |
relations | Object | 否 | 组件间关系定义,参见 组件间关系 |
options | Object Map | 否 | 一些组件选项,请参见文档其余部分的说明 |
生成的组件实例能够在组件的方法、生命周期函数和属性 observer
中经过 this
访问。组件包含一些通用属性和方法。
属性名 | 类型 | 描述 |
---|---|---|
is | String | 组件的文件路径 |
id | String | 节点id |
dataset | String | 节点dataset |
data | Object | 组件数据,包括内部数据和属性值 |
方法名 | 参数 | 描述 |
---|---|---|
setData | Object newData |
设置data并执行视图层渲染 |
hasBehavior | Object behavior |
检查组件是否具备 behavior (检查时会递归检查被直接或间接引入的全部behavior) |
triggerEvent | String name , Object detail , Object options |
触发事件,参见 组件事件 |
createSelectorQuery | 建立一个 SelectorQuery 对象,选择器选取范围为这个组件实例内 | |
selectComponent | String selector |
使用选择器选择组件实例节点,返回匹配到的第一个组件实例对象 |
selectAllComponents | String selector |
使用选择器选择组件实例节点,返回匹配到的所有组件实例对象组成的数组 |
getRelationNodes | String relationKey |
获取全部这个关系对应的全部关联节点,参见 组件间关系 |
代码示例:
Component({
behaviors: [],
properties: {
myProperty: { // 属性名
type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
value: '' // 属性初始值(可选),若是未指定则会根据类型选择一个
observer: function(newVal, oldVal){} // 属性被改变时执行的函数(可选),也能够写成在methods段中定义的方法名字符串
},
myProperty2: String // 简化的定义方式
},
data: {}, // 私有数据,可用于模版渲染
// 生命周期函数,能够为函数,或一个在methods段中定义的方法名
attached: function(){},
moved: function(){},
detached: function(){},
methods: {
onMyButtonTap: function(){
this.setData({
// 更新属性和数据的方法与更新页面数据的方法相似
})
},
_myPrivateMethod: function(){
// 内部方法建议如下划线开头
this.replaceDataOnPath(['A', 0, 'B'], 'myPrivateData') // 这里将 data.A[0].B 设为 'myPrivateData'
this.applyDataUpdates()
}
}
})
注意:在 properties
定义段中,属性名采用驼峰写法(propertyName
);在 wxml
中,指定属性值时则对应使用连字符写法(component-tag-name property-name="attr value"
),应用于数据绑定时采用驼峰写法(attr="{{propertyName}}"
)。
Tips:
Component
构造器构造的组件也能够做为页面使用。this.data
能够获取内部数据和属性值,但不要直接修改它们,应使用 setData
修改。this
访问到。dataXyz
这样的形式,由于在 WXML 中, data-xyz=""
会被做为节点 dataset 来处理,而不是组件属性。4. 组件事件返回顶部 |
事件系统是组件间交互的主要形式。自定义组件能够触发任意的事件,引用组件的页面能够监听这些事件。关于事件的基本概念和用法,参见 事件 。
监听自定义组件事件的方法与监听基础组件事件的方法彻底一致:
代码示例:
<!-- 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 --> <component-tag-name bindmyevent="onMyEvent" /> <!-- 或者能够写成 --> <component-tag-name bind:myevent="onMyEvent" />
Page({
onMyEvent: function(e){
e.detail // 自定义组件触发事件时提供的detail对象
}
})
自定义组件触发事件时,须要使用 triggerEvent
方法,指定事件名、detail对象和事件选项:
代码示例:
<!-- 在自定义组件中 --> <button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>
Component({
properties: {}
methods: {
onTap: function(){
var myEventDetail = {} // detail对象,提供给事件监听函数
var myEventOption = {} // 触发事件的选项
this.triggerEvent('myevent', myEventDetail, myEventOption)
}
}
})
触发事件的选项包括:
选项名 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
bubbles | Boolean | 否 | false | 事件是否冒泡 |
composed | Boolean | 否 | false | 事件是否能够穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其余任何组件内部 |
capturePhase | Boolean | 否 | false | 事件是否拥有捕获阶段 |
关于冒泡和捕获阶段的概念,请阅读 事件 章节中的相关说明。
代码示例:
// 页面 page.wxml <another-component bindcustomevent="pageEventListener1"> <my-component bindcustomevent="pageEventListener2"></my-component> </another-component>
// 组件 another-component.wxml <view bindcustomevent="anotherEventListener"> <slot /> </view>
// 组件 my-component.wxml <view bindcustomevent="myEventListener"> <slot /> </view>
// 组件 my-component.js
Component({
methods: {
onTap: function(){
this.triggerEvent('customevent', {}) // 只会触发 pageEventListener2
this.triggerEvent('customevent', {}, { bubbles: true }) // 会依次触发 pageEventListener2 、 pageEventListener1
this.triggerEvent('customevent', {}, { bubbles: true, composed: true }) // 会依次触发 pageEventListener2 、 anotherEventListener 、 pageEventListener1
}
}
})
5. behaviors返回顶部 |
behaviors
是用于组件间代码共享的特性,相似于一些编程语言中的“mixins”或“traits”。
每一个 behavior
能够包含一组属性、数据、生命周期函数和方法,组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。每一个组件能够引用多个 behavior
。 behavior
也能够引用其余 behavior
。
behavior
须要使用 Behavior()
构造器定义。
代码示例:
// my-behavior.js
module.exports = Behavior({
behaviors: [],
properties: {
myBehaviorProperty: {
type: String
}
},
data: {
myBehaviorData: {}
},
attached: function(){},
methods: {
myBehaviorMethod: function(){}
}
})
组件引用时,在 behaviors
定义段中将它们逐个列出便可。
代码示例:
// my-component.js
var myBehavior = require('my-behavior')
Component({
behaviors: [myBehavior],
properties: {
myProperty: {
type: String
}
},
data: {
myData: {}
},
attached: function(){},
methods: {
myMethod: function(){}
}
})
在上例中, my-component
组件定义中加入了 my-behavior
,而 my-behavior
中包含有 myBehaviorProperty
属性、 myBehaviorData
数据字段、 myBehaviorMethod
方法和一个 attached
生命周期函数。这将使得 my-component
中最终包含 myBehaviorProperty
、 myProperty
两个属性, myBehaviorData
、 myData
两个数据字段,和 myBehaviorMethod
、 myMethod
两个方法。当组件触发 attached
生命周期时,会依次触发 my-behavior
中的 attached
生命周期函数和 my-component
中的 attached
生命周期函数。
组件和它引用的 behavior
中能够包含同名的字段,对这些字段的处理方法以下:
behavior
中的属性或方法,若是引用了多个 behavior
,在定义段中靠后 behavior
中的属性或方法会覆盖靠前的属性或方法;behavior
被一个组件屡次引用,它定义的生命周期函数只会被执行一次。自定义组件能够经过引用内置的 behavior
来得到内置组件的一些行为。
代码示例:
Component({
behaviors: ['wx://form-field']
})
在上例中, wx://form-field
表明一个内置 behavior
,它使得这个自定义组件有相似于表单控件的行为。
内置 behavior
每每会为组件添加一些属性。在没有特殊说明时,组件能够覆盖这些属性来改变它的 type
或添加 observer
。
使自定义组件有相似于表单控件的行为。 form 组件能够识别这些自定义组件,并在 submit 事件中返回组件的字段名及其对应字段值。这将为它添加如下两个属性。
属性名 | 类型 | 描述 | 最低版本 |
---|---|---|---|
name | String | 在表单中的字段名 | 1.6.7 |
value | 任意 | 在表单中的字段值 | 1.6.7 |
6. 组件间关系返回顶部 |
有时须要实现这样的组件:
<custom-ul> <custom-li> item 1 </custom-li> <custom-li> item 2 </custom-li> </custom-ul>
这个例子中, custom-ul
和 custom-li
都是自定义组件,它们有相互间的关系,相互间的通讯每每比较复杂。此时在组件定义时加入 relations
定义段,能够解决这样的问题。示例:
// path/to/custom-ul.js
Component({
relations: {
'./custom-li': {
type: 'child', // 关联的目标节点应为子节点
linked: function(target) {
// 每次有custom-li被插入时执行,target是该节点实例对象,触发在该节点attached生命周期以后
},
linkChanged: function(target) {
// 每次有custom-li被移动后执行,target是该节点实例对象,触发在该节点moved生命周期以后
},
unlinked: function(target) {
// 每次有custom-li被移除时执行,target是该节点实例对象,触发在该节点detached生命周期以后
}
}
},
methods: {
_getAllLi: function(){
// 使用getRelationNodes能够得到nodes数组,包含全部已关联的custom-li,且是有序的
var nodes = this.getRelationNodes('path/to/custom-li')
}
},
ready: function(){
this._getAllLi()
}
})
// path/to/custom-li.js
Component({
relations: {
'./custom-ul': {
type: 'parent', // 关联的目标节点应为父节点
linked: function(target) {
// 每次被插入到custom-ul时执行,target是custom-ul节点实例对象,触发在attached生命周期以后
},
linkChanged: function(target) {
// 每次被移动后执行,target是custom-ul节点实例对象,触发在moved生命周期以后
},
unlinked: function(target) {
// 每次被移除时执行,target是custom-ul节点实例对象,触发在detached生命周期以后
}
}
}
})
注意:必须在两个组件定义中都加入relations定义,不然不会生效。
有时,须要关联的是一类组件,如:
<custom-form> <view> input <custom-input></custom-input> </view> <custom-submit> submit </custom-submit> </custom-form>
custom-form
组件想要关联 custom-input
和 custom-submit
两个组件。此时,若是这两个组件都有同一个behavior:
// path/to/custom-form-controls.js
module.exports = Behavior({
// ...
})
// path/to/custom-input.js
var customFormControls = require('./custom-form-controls')
Component({
behaviors: [customFormControls],
relations: {
'./custom-form': {
type: 'ancestor', // 关联的目标节点应为祖先节点
}
}
})
// path/to/custom-submit.js
var customFormControls = require('./custom-form-controls')
Component({
behaviors: [customFormControls],
relations: {
'./custom-form': {
type: 'ancestor', // 关联的目标节点应为祖先节点
}
}
})
则在 relations
关系定义中,可以使用这个behavior来代替组件路径做为关联的目标节点:
// path/to/custom-form.js
var customFormControls = require('./custom-form-controls')
Component({
relations: {
'customFormControls': {
type: 'descendant', // 关联的目标节点应为子孙节点
target: customFormControls
}
}
})
relations
定义段包含目标组件路径及其对应选项,可包含的选项见下表。
选项 | 类型 | 是否必填 | 描述 |
---|---|---|---|
type | String | 是 | 目标组件的相对关系,可选的值为 parent 、 child 、 ancestor 、 descendant |
linked | Function | 否 | 关系生命周期函数,当关系被创建在页面节点树中时触发,触发时机在组件attached生命周期以后 |
linkChanged | Function | 否 | 关系生命周期函数,当关系在页面节点树中发生改变时触发,触发时机在组件moved生命周期以后 |
unlinked | Function | 否 | 关系生命周期函数,当关系脱离页面节点树时触发,触发时机在组件detached生命周期以后 |
target | String | 否 | 若是这一项被设置,则它表示关联的目标节点所应具备的behavior,全部拥有这一behavior的组件节点都会被关联 |
7.返回顶部 |
8.返回顶部 |
9.返回顶部 |
10.返回顶部 |
11.返回顶部 |
![]() |
做者:ylbtech 出处:http://ylbtech.cnblogs.com/ 本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。 |