最近開(kāi)發(fā)小程序項(xiàng)目,小程序的的文檔挺詳細(xì)的,特別是官方提供了很多組件。但是,對(duì)于一些項(xiàng)目適用場(chǎng)景,官方所提供的組件是無(wú)法滿足的。這時(shí)候,需要我們自己去開(kāi)發(fā)一個(gè)自定義組件,來(lái)滿足當(dāng)前項(xiàng)目的需求。
如何創(chuàng)建一個(gè)自定義組件
從小程序基礎(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ǔ)組件非常相似。
首先,我們需要新建一個(gè) components 文件夾,用于存放我們以后開(kāi)發(fā)中的所用組件,我們?cè)?components 組件中新建一個(gè) module文件夾來(lái)存放我們的組件,在 module下右擊新建 Component 并命名為 module后,會(huì)生成對(duì)應(yīng)的 json wxml wxss js 4個(gè)文件,這就是一個(gè)自定義組件的組成部分,這樣組件初始化工作已完成。同時(shí)我們還需要聲明組件,需要在module. json 文件中進(jìn)行自定義組件聲明(將 component 字段設(shè)為 true ):
{
"component": true,
"usingComponents": {}
}
同時(shí),還要在 wxml 文件中編寫組件模版,在 wxss 文件中加入組件樣式,它們的寫法與頁(yè)面的寫法類似。具體細(xì)節(jié)和注意事項(xiàng)參見(jiàn) 組件模版和樣式 。下面為一個(gè)組件的完整結(jié)構(gòu)。
<!-- 這是自定義組件的內(nèi)部WXML結(jié)構(gòu) -->
<view class="inner">
{{innerText}}
<button type='primary' bindtap='change'>子組件點(diǎn)擊按鈕</button>
</view>
<slot></slot>
<slot name="homePage"></slot>
/* 這里的樣式只應(yīng)用于這個(gè)自定義組件wxss結(jié)構(gòu) */
.inner {
color: red;
}
在自定義組件的js文件中,需要使用 Component() 來(lái)注冊(cè)組件,并提供組件的屬性定義、內(nèi)部數(shù)據(jù)和自定義方法,
/* 這個(gè)自定義組件js結(jié)構(gòu) */
Component({
options: {
multipleSlots: true // 在組件定義時(shí)的選項(xiàng)中啟用多slot支持
},
properties: {
// 這里定義了innerText屬性,屬性值可以在組件使用時(shí)指定
innerText: {
type: String,
value: 'default value',
}
},
data: {
// 這里是一些組件內(nèi)部數(shù)據(jù)
someData: {}
},
methods: {
// 這里是一個(gè)自定義方法
change: function(){
// 子組件觸發(fā)事件傳給父頁(yè)面
this.triggerEvent("change")
},
// 子組件自己的方法
childrenFunction(){
console.log('我被父組件調(diào)用了')
}
}
})
如何使用一個(gè)自定義組件
既然是組件,必然是在頁(yè)面引入使用的,我們一般稱該頁(yè)面為父頁(yè)面。首先,我們應(yīng)該在要用組件的那個(gè)頁(yè)面中(父頁(yè)面)引用聲明.也就是在.json文件。如index.json文件:
"usingComponents": {
"module": "/components/module/module"
}
當(dāng)我們引入組件之后,就可在父頁(yè)面使用該自定義組件了。
父頁(yè)面如何將數(shù)據(jù)傳給子組件呢?
父頁(yè)面通過(guò)inner-text將數(shù)據(jù)傳給子組件,子組件通過(guò)innerText來(lái)接受父頁(yè)面?zhèn)鬟^(guò)來(lái)的父頁(yè)面變量text的數(shù)據(jù)。
父頁(yè)面該如何獲取子組的data,以及子組件的方法?
我們?cè)谝虢M件時(shí),給子組件設(shè)置一個(gè)id,通過(guò)this.selectComponent('#module')的方法來(lái)獲取module組件,即獲得了該組件里的所有內(nèi)容,包括data里的內(nèi)容(this.module.data),以及方法的調(diào)用(this.module.childrenFunction())。
子組件如何調(diào)用父頁(yè)面的方法呢?
通過(guò)this.triggerEvent("change")方法,將子組件觸發(fā)的事件傳給父頁(yè)面,父頁(yè)面通過(guò)bind綁定一個(gè)方法來(lái)接受子組件傳過(guò)來(lái)的change事件方法,從而調(diào)用到父組件的方法。triggerEvent()函數(shù)有三個(gè)參數(shù),第一個(gè)參數(shù)為暴露給父節(jié)點(diǎn)的事件類型。第二個(gè)參數(shù)為向父組件傳遞的數(shù)據(jù),第三個(gè)參數(shù)為選項(xiàng),傳入對(duì)象進(jìn)去。
組件slot的理解?
slot與vue插槽很類似,有了slot的話,可以使組件更加靈活使用。例如,一個(gè)組件的的某些內(nèi)容在不同頁(yè)面引用所展示的內(nèi)容不一樣,這時(shí)我們使用slot來(lái)實(shí)現(xiàn)。name為homePage的slot,我們?cè)趇ndex.wxml使用了,而在別的頁(yè)面未使用的話,別的頁(yè)面就不會(huì)顯示<view name="homePage"></view>里的內(nèi)容。
具體如下:
<!-- 父頁(yè)面 -->
<!-- 頁(yè)面的 WXML -->
<view class="container">
<module
id='module'
inner-text="{{text}}"
bind:change="change">
<view>這里是插入到組件slot中的內(nèi)容</view>
<view name='homePage'>這里插入到組件homePage的slot中的內(nèi)容</view>
</module>
<button type='primary' style='height: 40px;' bindtap='childrenFunction'>父頁(yè)面調(diào)用子組件方法</button>
</view>
//index.js
// 獲取應(yīng)用實(shí)例
const app = getApp()
Page({
data: {
text: '初始值1'
}
/* 生命周期函數(shù)--監(jiān)聽(tīng)頁(yè)面初次渲染完成*/
onReady: function () {
// 獲得module組件
this.module = this.selectComponent('#module');
}
// 點(diǎn)擊事件
change() {
console.log('moudule組件點(diǎn)擊事件')
this.setData({
text: '子組件點(diǎn)擊事件改變了我'
})
}
// 父頁(yè)面調(diào)用子組件的方法
childrenFunction(){
this.module.childrenFunction()
}
})
后記
微信小程序中自定義組件的用法還有很多, 調(diào)用Component構(gòu)造器時(shí)可以指定組件的屬性、數(shù)據(jù)、方法等,更多的內(nèi)容可以參考官方文檔.