微信小程序自定义组件详解
自定義組件能夠幫我們更好的復(fù)用代碼和重構(gòu)簡(jiǎn)化代碼復(fù)雜度。一起來(lái)學(xué)習(xí)一下小程序自定義組件的內(nèi)容吧。
從小程序基礎(chǔ)庫(kù)版本 1.6.3 開(kāi)始,小程序支持簡(jiǎn)潔的組件化編程。所有自定義組件相關(guān)特性都需要基礎(chǔ)庫(kù)版本 1.6.3 或更高。
開(kāi)發(fā)者可以將頁(yè)面內(nèi)的功能模塊抽象成自定義組件,以便在不同的頁(yè)面中重復(fù)使用;也可以將復(fù)雜的頁(yè)面拆分成多個(gè)低耦合的模塊,有助于代碼維護(hù)。自定義組件在使用時(shí)與基礎(chǔ)組件非常相似
總覽
一、Component概念
Component像頁(yè)面一樣由wxml、wxss、js和json4個(gè)文件組成,且需要把這4個(gè)文件放在同一個(gè)目錄中。與頁(yè)面不一樣的是,Component中的構(gòu)造函數(shù)(也可以稱構(gòu)造器)是Component({}),而頁(yè)面中的構(gòu)造函數(shù)是Page({})。要編寫(xiě)一個(gè)自定義組件,首先需要在 json 文件中進(jìn)行自定義組件聲明(將component字段設(shè)為true可這一組文件設(shè)為自定義組件):
{
"component": true
}
slot
Component的slot(slot意思是插槽),主要是讓你在外部的wxml可以自由的在你的Component的wxml里插入模塊。默認(rèn)情況下,一個(gè)組件的wxml只可能有一個(gè)slot。需要使用多個(gè)時(shí),可以在組件js中聲明啟用。
Component({
options: {
multipleSlots: true // 在組件定義時(shí)的選項(xiàng)中啟用多slot支持
},
properties: { /* ... */ },
methods: { /* ... */ }
})
此時(shí),可以在這個(gè)組件的wxml中使用多個(gè)slot,以不同的 name 來(lái)區(qū)分。
<!-- 組件模板 --> <view class="wrapper"> <slot name="before"></slot> <view>這里是組件的內(nèi)部細(xì)節(jié)</view> <slot name="after"></slot> </view>
使用時(shí),用 slot 屬性來(lái)將節(jié)點(diǎn)插入到不同的slot上。
<!-- 引用組件的頁(yè)面模板 -->
<view>
<component-tag-name>
<!-- 這部分內(nèi)容將被放置在組件 <slot name="before"> 的位置上 -->
<view slot="before">這里是插入到組件slot name="before"中的內(nèi)容</view>
<!-- 這部分內(nèi)容將被放置在組件 <slot name="after"> 的位置上 -->
<view slot="after">這里是插入到組件slot name="after"中的內(nèi)容</view>
</component-tag-name>
</view>
組件樣式編寫(xiě)注意事項(xiàng)
- 組件和引用組件的頁(yè)面不能使用id選擇器(#a)、屬性選擇器([a])和標(biāo)簽名選擇器,請(qǐng)改用class選擇器。
- 組件和引用組件的頁(yè)面中使用后代選擇器(.a .b)在一些極端情況下會(huì)有非預(yù)期的表現(xiàn),如遇,請(qǐng)避免使用。
- 子元素選擇器(.a>.b)只能用于 view 組件與其子節(jié)點(diǎn)之間,用于其他組件可能導(dǎo)致非預(yù)期的情況。
- 繼承樣式,如 font 、 color ,會(huì)從組件外繼承到組件內(nèi)。
- 除繼承樣式外, app.wxss 中的樣式、組件所在頁(yè)面的的樣式對(duì)自定義組件無(wú)效。
#a { } /* 在組件中不能使用 */
[a] { } /* 在組件中不能使用 */
button { } /* 在組件中不能使用 */
.a > .b { } /* 除非 .a 是 view 組件節(jié)點(diǎn),否則不一定會(huì)生效 */
外部樣式類
使用外部樣式類可以讓組件使用指定的組件外樣式類,如果希望組件外樣式類能夠完全影響組件內(nèi)部,可以將組件構(gòu)造器中的options.addGlobalClass字段置為true。
/* 組件 custom-component.js */
Component({
externalClasses: ['my-class']
})
<!-- 組件 custom-component.wxml --> <custom-component class="my-class">這段文本的顏色由組件外的 class 決定</custom-component>
/* 組件外的樣式定義 */
.red-text {
color: red;
}
創(chuàng)建一個(gè)組件
一個(gè)組件需要包括json、wxml、wxss、js四個(gè)文件組成,下面我們先看看一個(gè)簡(jiǎn)單的入門(mén):
<!--components/component/component.wxml-->
<view class="inner">
{{innerText}}
</view>
<slot></slot>
編寫(xiě)JS文件,組件的屬性值和內(nèi)部數(shù)據(jù)將被用于組件 wxml 的渲染,其中,屬性值是可由組件外部傳入的
// components/component/component.js
Component({
/**
* 組件的屬性列表
*/
properties: {
innerText: {
type: String,
value: 'hello world'
},
myProperties:String
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
},
/**
* 組件的方法列表
*/
methods: {
}
})
設(shè)置字體的顏色
/* components/component/component.wxss */
.inner{color: red;}
完成對(duì)組件的初始化,包括設(shè)置屬性列表,初始化數(shù)據(jù),以及設(shè)置相關(guān)的方法。
使用自定義組件
使用已注冊(cè)的自定義組件前,首先要在頁(yè)面的 json 文件中進(jìn)行引用聲明。此時(shí)需要提供每個(gè)自定義組件的標(biāo)簽名和對(duì)應(yīng)的自定義組件文件路徑:
{
"usingComponents": {
"component": "/components/component/component"
}
}
在page頁(yè)面下添加聲明過(guò)的自定義組件:
<component></component>
<view>
<component>
<!-- 這部分內(nèi)容將被放置在組件 <slot> 的位置上 -->
<view>這里是插入到組件slot中的內(nèi)容</view>
</component>
</view>
上方的是一個(gè)最簡(jiǎn)單的自定義組件。
注意事項(xiàng):
1.對(duì)于基礎(chǔ)庫(kù)的1.5.x版本, 1.5.7 也有部分自定義組件支持。
2.因?yàn)閃XML節(jié)點(diǎn)標(biāo)簽名只能是小寫(xiě)字母、中劃線和下劃線的組合,所以自定義組件的標(biāo)簽名也只能包含這些字符。
3.自定義組件也是可以引用自定義組件的,引用方法類似于頁(yè)面引用自定義組件的方式(使用 usingComponents 字段)。
4.自定義組件和使用自定義組件的頁(yè)面所在項(xiàng)目根目錄名不能以“wx-”為前綴,否則會(huì)報(bào)錯(cuò)。
5.舊版本的基礎(chǔ)庫(kù)不支持自定義組件,此時(shí),引用自定義組件的節(jié)點(diǎn)會(huì)變?yōu)槟J(rèn)的空節(jié)點(diǎn)。
Component構(gòu)造器
使用component構(gòu)造器,進(jìn)行構(gòu)造。 該構(gòu)造函數(shù)用于定義組件。調(diào)用Component函數(shù)能指定組件的數(shù)據(jù),屬性和方法。來(lái)看看這個(gè)完整的列表代碼含義:
Component({
behaviors: [],
properties: {
myProperty: { // 屬性名
type: String, // 類型(必填),目前接受的類型包括:String, Number, Boolean, Object, Array, null(表示任意類型)
value: '', // 屬性初始值(可選),如果未指定則會(huì)根據(jù)類型選擇一個(gè)
observer: function (newVal, oldVal) {
this._propertyChange(newVal, oldVal);
} // 屬性被改變時(shí)執(zhí)行的函數(shù)(可選),也可以寫(xiě)成在methods段中定義的方法名字符串, 如:'_propertyChange'
},
myProperty2: String // 簡(jiǎn)化的定義方式
},
data: {
A: [{
B: 'init data.A[0].B'
}]
}, // 私有數(shù)據(jù),可用于模版渲染
lifetimes: {
// 生命周期函數(shù),可以為函數(shù),或一個(gè)在methods段中定義的方法名
attached: function () { },
moved: function () { },
detached: function () { },
},
// 生命周期函數(shù),可以為函數(shù),或一個(gè)在methods段中定義的方法名
attached: function () { }, // 此處attached的聲明會(huì)被lifetimes字段中的聲明覆蓋
ready: function() { },
pageLifetimes: {
// 組件所在頁(yè)面的生命周期函數(shù)
show: function () { },
},
methods: {
onMyButtonTap: function () {
this.setData({
// 更新屬性和數(shù)據(jù)的方法與更新頁(yè)面數(shù)據(jù)的方法類似
myProperty: 'Test'
})
},
_myPrivateMethod: function () {
// 內(nèi)部方法建議以下劃線開(kāi)頭
this.replaceDataOnPath(['A', 0, 'B'], 'myPrivateData') // 這里將 data.A[0].B 設(shè)為 'myPrivateData'
this.applyDataUpdates()
},
_propertyChange: function (newVal, oldVal) {
console.log(newVal);
console.log(oldVal);
}
}
})
組件與數(shù)據(jù)通信
組件間的通信方法有以下幾種:
- WXML 數(shù)據(jù)綁定:用于父組件向子組件的指定屬性設(shè)置數(shù)據(jù),僅能設(shè)置 JSON 兼容數(shù)據(jù)(自基礎(chǔ)庫(kù)版本 2.0.9 開(kāi)始,還可以在數(shù)據(jù)中包含函數(shù))。具體在 組件模板和樣式 章節(jié)中介紹。
- 事件:用于子組件向父組件傳遞數(shù)據(jù),可以傳遞任意數(shù)據(jù)。
- 如果以上兩種方式不足以滿足需要,父組件還可以通過(guò)?this.selectComponent?方法獲取子組件實(shí)例對(duì)象,這樣就可以直接訪問(wèn)組件的任意數(shù)據(jù)和方法。
通過(guò)在頁(yè)面中給組件加了一個(gè)id值,這樣子我們就能查到組件的方法了。
<compontent id="modal"></compontent>
/*js*/
var modal = this.setlectComponet('#modal');
這樣子就能在外面調(diào)用組件里面的任意數(shù)據(jù)和方法了。
- properties:主頁(yè)面?zhèn)魅霐?shù)據(jù)到組件,相當(dāng)于vue的props,是傳入外部數(shù)據(jù)的入口。
- data:則用于組件的內(nèi)部數(shù)據(jù)變化,外部數(shù)據(jù)沒(méi)法初始化
在 properties 定義段中,屬性名采用駝峰寫(xiě)法(propertyName);在 wxml 中,指定屬性值時(shí)則對(duì)應(yīng)使用連字符寫(xiě)法(component-tag-name property-name="attr value"),應(yīng)用于數(shù)據(jù)綁定時(shí)采用駝峰寫(xiě)法(attr="{{propertyName}}")
傳入的數(shù)據(jù),不管是簡(jiǎn)單數(shù)據(jù)類型,還是引用類型,都如同值復(fù)制一樣
方法函數(shù)調(diào)用
methods:需要在組件中調(diào)用的方法,都寫(xiě)在這個(gè)對(duì)象里面。跟Page中的對(duì)象里面的方法同級(jí)。
生命周期:可單獨(dú)某個(gè)生命周期放在Components下(舊式的定義方式,可以保持對(duì) <2.2.3 版本基礎(chǔ)庫(kù)的兼容),也可以放在lifetimes,如果兩個(gè)地方有同名生命周期,則lifetimes里面的方法會(huì)覆蓋前者。
Component({
lifetimes: {
attached: function() {
// 在組件實(shí)例進(jìn)入頁(yè)面節(jié)點(diǎn)樹(shù)時(shí)執(zhí)行
},
detached: function() {
// 在組件實(shí)例被從頁(yè)面節(jié)點(diǎn)樹(shù)移除時(shí)執(zhí)行
},
},
// 以下是舊式的定義方式,可以保持對(duì) <2.2.3 版本基礎(chǔ)庫(kù)的兼容
attached: function() {
// 在組件實(shí)例進(jìn)入頁(yè)面節(jié)點(diǎn)樹(shù)時(shí)執(zhí)行
},
detached: function() {
// 在組件實(shí)例被從頁(yè)面節(jié)點(diǎn)樹(shù)移除時(shí)執(zhí)行
},
// ...
})
組件所在的生命周期
還有一些特殊的生命周期,它們并非與組件有很強(qiáng)的關(guān)聯(lián),但有時(shí)組件需要獲知,以便組件內(nèi)部處理。這樣的生命周期稱為“組件所在頁(yè)面的生命周期”,在 pageLifetimes 定義段中定義。其中可用的生命周期包括:
生成的組件實(shí)例可以在組件的方法、生命周期函數(shù)和屬性 observer 中通過(guò) this 訪問(wèn)。組件包含一些通用屬性和方法
image.png
組件傳出數(shù)據(jù)到主頁(yè)面
組件間交互的主要形式是自定義事件。
組件通過(guò) this.triggerEvent() 觸發(fā)自定義事件,主頁(yè)面在組件上 bind:myevent="onMyEvent" 來(lái)接收自定義事件。
其中,this.triggerEvent() 方法接收自定義事件名稱外,還接收兩個(gè)對(duì)象,eventDetail 和 eventOptions。
<!-- 在自定義組件中 --> <button bindtap="onTap">點(diǎn)擊這個(gè)按鈕將觸發(fā)“myevent”事件</button>
Component({
properties: {}
methods: {
// 子組件觸發(fā)自定義事件
ontap () {
// 所有要帶到主頁(yè)面的數(shù)據(jù),都裝在eventDetail里面
var eventDetail = {
name:'sssssssss',
test:[1,2,3]
}
// 觸發(fā)事件的選項(xiàng) bubbles是否冒泡,composed是否可穿越組件邊界,capturePhase 是否有捕獲階段
var eventOption = {
composed: true
}
this.triggerEvent('myevent', eventDetail, eventOption)
}
}
})
觸發(fā)的事件包括:
監(jiān)聽(tīng)事件
自定義組件可以觸發(fā)任意的事件,引用組件的頁(yè)面可以監(jiān)聽(tīng)這些事件。監(jiān)聽(tīng)自定義組件事件的方法與監(jiān)聽(tīng)基礎(chǔ)組件事件的方法完全一致:
在Page事件中監(jiān)聽(tīng)組件中傳遞過(guò)來(lái)的值。
Page({
onMyEvent: function(e){
e.detail // 自定義組件觸發(fā)事件時(shí)提供的detail對(duì)象
}
})
behaviors
behaviors 是用于組件間代碼共享的特性,類似于一些編程語(yǔ)言中的“mixins”或“traits”。
每個(gè) behavior 可以包含一組屬性、數(shù)據(jù)、生命周期函數(shù)和方法,組件引用它時(shí),它的屬性、數(shù)據(jù)和方法會(huì)被合并到組件中,生命周期函數(shù)也會(huì)在對(duì)應(yīng)時(shí)機(jī)被調(diào)用。每個(gè)組件可以引用多個(gè) behavior 。 behavior 也可以引用其他 behavior 。
// my-behavior.js
module.exports = Behavior({
behaviors: [],
properties: {
myBehaviorProperty: {
type: String
}
},
data: {
myBehaviorData: {}
},
attached: function(){},
methods: {
myBehaviorMethod: function(){}
}
})
組件引用時(shí),在 behaviors 定義段中將它們逐個(gè)列出即可。
// my-component.js
var myBehavior = require('my-behavior')
Component({
behaviors: [myBehavior],
properties: {
myProperty: {
type: String
}
},
data: {
myData: {}
},
attached: function(){},
methods: {
myMethod: function(){}
}
})
字段的覆蓋和組合規(guī)則
組件和它引用的 behavior 中可以包含同名的字段,對(duì)這些字段的處理方法如下:
如果有同名的屬性或方法,組件本身的屬性或方法會(huì)覆蓋 behavior 中的屬性或方法,如果引用了多個(gè) behavior ,在定義段中靠后 behavior 中的屬性或方法會(huì)覆蓋靠前的屬性或方法;
如果有同名的數(shù)據(jù)字段,如果數(shù)據(jù)是對(duì)象類型,會(huì)進(jìn)行對(duì)象合并,如果是非對(duì)象類型則會(huì)進(jìn)行相互覆蓋;
生命周期函數(shù)不會(huì)相互覆蓋,而是在對(duì)應(yīng)觸發(fā)時(shí)機(jī)被逐個(gè)調(diào)用。如果同一個(gè) behavior 被一個(gè)組件多次引用,它定義的生命周期函數(shù)只會(huì)被執(zhí)行一次。
內(nèi)置behavior
組件間關(guān)系
<custom-ul> <custom-li> item 1 </custom-li> <custom-li> item 2 </custom-li> </custom-ul>
這個(gè)例子中, custom-ul 和 custom-li 都是自定義組件,它們有相互間的關(guān)系,相互間的通信往往比較復(fù)雜。此時(shí)在組件定義時(shí)加入 relations 定義段,可以解決這樣的問(wèn)題。示例:
// path/to/custom-ul.js
Component({
relations: {
'./custom-li': {
type: 'child', // 關(guān)聯(lián)的目標(biāo)節(jié)點(diǎn)應(yīng)為子節(jié)點(diǎn)
linked: function(target) {
// 每次有custom-li被插入時(shí)執(zhí)行,target是該節(jié)點(diǎn)實(shí)例對(duì)象,觸發(fā)在該節(jié)點(diǎn)attached生命周期之后
},
linkChanged: function(target) {
// 每次有custom-li被移動(dòng)后執(zhí)行,target是該節(jié)點(diǎn)實(shí)例對(duì)象,觸發(fā)在該節(jié)點(diǎn)moved生命周期之后
},
unlinked: function(target) {
// 每次有custom-li被移除時(shí)執(zhí)行,target是該節(jié)點(diǎn)實(shí)例對(duì)象,觸發(fā)在該節(jié)點(diǎn)detached生命周期之后
}
}
},
methods: {
_getAllLi: function(){
// 使用getRelationNodes可以獲得nodes數(shù)組,包含所有已關(guān)聯(lián)的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', // 關(guān)聯(lián)的目標(biāo)節(jié)點(diǎn)應(yīng)為父節(jié)點(diǎn)
linked: function(target) {
// 每次被插入到custom-ul時(shí)執(zhí)行,target是custom-ul節(jié)點(diǎn)實(shí)例對(duì)象,觸發(fā)在attached生命周期之后
},
linkChanged: function(target) {
// 每次被移動(dòng)后執(zhí)行,target是custom-ul節(jié)點(diǎn)實(shí)例對(duì)象,觸發(fā)在moved生命周期之后
},
unlinked: function(target) {
// 每次被移除時(shí)執(zhí)行,target是custom-ul節(jié)點(diǎn)實(shí)例對(duì)象,觸發(fā)在detached生命周期之后
}
}
}
})
更多:
- 關(guān)聯(lián)一類組件
- 抽象節(jié)點(diǎn)
- 自定義組件擴(kuò)展
- 開(kāi)發(fā)第三方自定義組件
制作一個(gè)彈窗組件
https://developers.weixin.qq.com/s/M55masmW764P
PPT:https://ppt.baomitu.com/d/baf2b116
總結(jié)
以上是生活随笔為你收集整理的微信小程序自定义组件详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 自卑症状
- 下一篇: 关于孟子的名言名句223个