一储笑、自定義組件介紹
微信小程序提供了自定義組件擴(kuò)展機(jī)制,允許我們使用自定義組件的方式來構(gòu)建頁面。
自定義組件可以使我們更好的復(fù)用一些功能伏钠。
二、創(chuàng)建自定義組件
在項(xiàng)目的pages文件夾
下創(chuàng)建文件夾坏怪,例如customComponent文件
夾贝润,然后右鍵這個文件夾绊茧,選擇新建Component铝宵,這時customComponent文件夾
出現(xiàn)四個文件,和正常的創(chuàng)建的一樣华畏,下面介紹這四個文件和正常的不同之處:
#CusComponent.js:
Component({
/**
* 組件的屬性列表
*/
properties: {
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
},
/**
* 組件的方法列表
*/
methods: {
}
})
#CusComponent.json
{
"component": true, //代表當(dāng)前文件是一個組件
"usingComponents": {} //使用組件寫在括號里
}
js文件的頭有Page
變?yōu)?code>Component鹏秋,json文件里面多了"component": true,
。wxml
和wxss
文件和原來的一樣亡笑。
三侣夷、如何使用自定義組件
想在主頁index
頁面使用組件,那么打開存放頁面的pages
文件夾下的index
文件夾中的index.json
仑乌,在usingComponents
中添加如下代碼:
{
"usingComponents": {
"CusComponent":"/pages/customComponent/cusComponent"
}
}
usingComponents
里面是鍵值對百拓,左邊是要使用組件的名字,右邊是其路徑晰甚。
接著在index.wxml
中使用<CusComponent></CusComponent>
引入組件衙传。
四、自定義組件中.js
文件的屬性介紹
-
data屬性:組件的初始數(shù)據(jù)
例如添加如下數(shù)據(jù):
#js文件中的data屬性:
data: {
itemList:[
{id:0,name:"首頁"},
{id:1,name:"類別"},
{id:2,name:"關(guān)于"},
]
}
此時在wxml
文件中可以像下面這樣寫:
<view wx:for="{{itemList}}" wx:key="key">{{item.name}}</view>
結(jié)果:首頁 類別 關(guān)于
因?yàn)?code>wx:for中列表遍歷默認(rèn)的是item厕九,所以可以直接用item.name
來獲取name
蓖捶。
-
methods屬性:組件的方法列表
在正常頁面中方法是存放在.js文件
中data屬性
的同層級下的。而在自定義組件中必須放在.js文件
的methods
里面扁远,放在外面方法無效俊鱼。
<view bindTap="handleMethod"></view>
methods: {
handleMethod(e){
//語句let itemList = this.data.itemList;和下面的相等,解構(gòu)
let {itemList} = this.data;
//[].forEach遍歷數(shù)組畅买,遍歷的時候修改了v并闲,也會導(dǎo)致源數(shù)組被修改
//使用這種寫法則相當(dāng)于重新拷貝了一份數(shù)據(jù)let items = JSON.parse(JSON.stringify(this.data.itemList));
itemList.forEach((v,i) => i===index?v.isActive=true:v.isActive=false)
}
}
-
properties屬性:組件的對外屬性,是屬性名到屬性設(shè)置的映射表谷羞。里面存放的是父組件傳遞過來的數(shù)據(jù)
參見:五焙蚓、父組件向子組件傳值 -
options屬性:配置一些功能的選項(xiàng)
可配置的選項(xiàng):
multipleSlots:true,在組件定義時的選項(xiàng)中啟動多slot支持
styleIsolation:isolated,啟動樣式隔離购公,具體配置選項(xiàng)參見:(八)自定義組件的樣式
addGlobalClass:true萌京,表示頁面 wxss 樣式將影響到自定義組件,但自定義組件 wxss 中指定的樣式不會影響頁面宏浩。這個選項(xiàng)等價于設(shè)置 styleIsolation: apply-shared
virtualHost:true知残,將自定義節(jié)點(diǎn)設(shè)置成虛擬的,我們不希望自定義組件的這個節(jié)點(diǎn)本身可以設(shè)置樣式比庄、響應(yīng) flex 布局等求妹,而是希望自定義組件內(nèi)部的第一層節(jié)點(diǎn)能夠響應(yīng) flex 布局或者樣式由自定義組件本身完全決定。
/* 組件 custom-component.js */
Component({
options: {
addGlobalClass: true,
}
})
- 其他屬性:
屬性 | 類型 | 是否必填 | 描述 |
---|---|---|---|
properties | Object|Map | 否 | 組件的對外屬性佳窑,是屬性名到屬性設(shè)置的映射表 |
data | Object | 否 | 組件的內(nèi)部數(shù)據(jù)制恍,和properties用用于組件的模版渲染 |
observers | Object | 否 | 組件數(shù)據(jù)字段監(jiān)聽器,用于監(jiān)聽properties和data的變化 |
methods | Object | 否 | 組件的方法神凑,包括事件響應(yīng)函數(shù)和任意的自定義方法 |
created | Function | 否 | 組件生命周期函數(shù)净神,在組件實(shí)例剛剛被創(chuàng)建時執(zhí)行,注意此時不能調(diào)用setData |
attached | Function | 否 | 組件生命周期函數(shù)溉委,在組件實(shí)例進(jìn)入頁面節(jié)點(diǎn)樹時執(zhí)行 |
ready | Function | 否 | 組件生命周期函數(shù)鹃唯,在組件布局完成后執(zhí)行 |
moved | Function | 否 | 組件生命周期函數(shù),在組件實(shí)例被移動到節(jié)點(diǎn)樹另一個位置時執(zhí)行 |
detached | Function | 否 | 組件生命周期函數(shù)瓣喊,在組件實(shí)例被從頁面節(jié)點(diǎn)樹移除時執(zhí)行 |
五坡慌、父組件向子組件傳值
直接看代碼:
#父組件的wxml文件,在此文件中引入CusComponent組件
//parentData為要傳遞的數(shù)據(jù)名稱藻三,parent_data為數(shù)據(jù)內(nèi)容
<CusComponent parentData="parent_data"></CusComponent>
#自定義組件的.js文件里的properties屬性
properties: {
//要接收的數(shù)據(jù)名稱
parentData:{
//要接收的數(shù)據(jù)類型
type:String,
//要接收的數(shù)據(jù)
value:''
}
}
<!-- 自定義組件的wxml文件 -->
<view wx:for="{{itemList}}" wx:key="key">{{item.name}}</view>
<!-- parentData就是要接收數(shù)據(jù)的名稱 -->
<view class="content">{{parentData}}</view>
過程:
1洪橘、父組件通過parentData="parent_data"
將數(shù)據(jù)傳到子組件
2、子組件的properties
接收到數(shù)據(jù)后棵帽,根據(jù)父組件數(shù)據(jù)名parentData
熄求,存到parentData
的value
3、子組件的wxml文件
直接使用{{parentData}}
來拿到父組件傳遞過來的數(shù)據(jù)岖寞。
六抡四、子組件向父組件傳值
子組件給父組件傳遞數(shù)據(jù)通過自定義組件觸發(fā)事件來進(jìn)行傳遞。先看代碼:
#子組件的.js文件
methods: {
handleActive(e){
const {index} = e.currentTarget.dataset;
//triggerEvent("自定義事件名稱",要傳遞的數(shù)據(jù))仗谆,觸發(fā)事件
this.triggerEvent("itemChange",{index});
}
}
#父組件的wxml文件
<!--
當(dāng)子組件事件觸發(fā)后指巡,bindbinditemChange會執(zhí)行其后的方法changeItemList()
binditemChange="changeItemList";
1、binditemChange:其格式是bind+事件名稱隶垮,事件的名稱是子組件中this.triggerEvent("itemChange",{index});的事件名稱
2藻雪、changeItemList():是父組件.js文件中的方法
-->
< CusComponent itemList="{{itemList}}" binditemChange="changeItemList"></CusComponent>
#父組件.js文件中的方法
changeItemList(e){
const index = e.detail.index;
let itemList = this.data.itemList;
itemList.forEach((v,i) => {
i===index?v.isActive=true:v.isActive=false
});
this.setData({
itemList:itemList
})
}
過程:
1、點(diǎn)擊子組件后調(diào)用子組件的handleActive(e)
狸吞,此方法中有個自定義組件觸發(fā)事件this.triggerEvent("itemChange",{index});
2勉耀、觸發(fā)父組件wxml文件
引用的<CusComponent/>
組件中的binditemChange
指向的changeItemList()
方法
3指煎、在父組件的.js文件
中的changeItemList()
方法中對子組件傳遞過來的數(shù)據(jù)進(jìn)行處理
- triggerEvent方法參數(shù):triggerEvent('myevent',{myEventDetail},{myEventOption});
triggerEvent方法三個參數(shù)解釋:
?'myevent':自定義事件的名稱
?myEventDetail:detail對象,提供給事件監(jiān)聽函數(shù)便斥,如上面?zhèn)鬟f的數(shù)據(jù)
?myEventOption:觸發(fā)事件的選項(xiàng)至壤,不是必填項(xiàng)。
myEventOption的三個選項(xiàng)解釋:
?bubbles:事件是否冒泡枢纠。默認(rèn)值false
?composed:事件是否可以穿越組件邊界像街,為false時,事件將只能在引用組件的節(jié)點(diǎn)樹上觸發(fā)晋渺,不進(jìn)入其他任何組件內(nèi)部镰绎。默認(rèn)值false
?capturePhase:事件是否擁有捕獲階段。默認(rèn)值false
七木西、自定義組件中的 slot 標(biāo)簽
組件的寫法和頁面相同畴栖。組件與組件數(shù)據(jù)結(jié)合后生產(chǎn)的節(jié)點(diǎn)樹,將被插入到組件的引用位置上八千。
在組件中提供了一個<slot>
節(jié)點(diǎn)吗讶,用于承載組件引用時提供的子節(jié)點(diǎn)。
注意:在模板中引用到的自定義組件及其對應(yīng)的節(jié)點(diǎn)名需要在 json
文件中顯式定義叼丑,否則會被當(dāng)作一個無意義的節(jié)點(diǎn)关翎。除此以外扛门,節(jié)點(diǎn)名也可以被聲明為抽象節(jié)點(diǎn)鸠信。
#父組件wxml中引用的子組件
<cusComponent>
<view>父組件傳遞過來的節(jié)點(diǎn),相當(dāng)于子組件中的slot</view>
</cusComponent>
#子組件wxml中
<view class="content">
<slot></slot>
</view>
上面的代碼就會讓父組件傳遞過來的節(jié)點(diǎn)论寨,相當(dāng)于子組件中的slot
在你的自定義組件中顯示星立。
需要多個slot
時,如何在組件js中聲明:
#子組件的.js文件
Component({
options: {
multipleSlots: true // 在組件定義時的選項(xiàng)中啟用多slot支持
},
})
此時就可以在組件的wxml
中使用多個slot
葬凳,以不用的name來區(qū)分:
#子組件的.wxml文件
<view class="content">
<slot name="name1"></slot>
<slot name="name2"></slot>
</view>
八绰垂、自定義組件的樣式
1、組件樣式
組件對應(yīng) wxss 文件的樣式火焰,只對組件wxml內(nèi)的節(jié)點(diǎn)生效劲装。編寫組件樣式時,需要注意以下幾點(diǎn):
- 請使用class選擇器:組件和引用組件的頁面不能使用id選擇器(#a)昌简、屬性選擇器([a])和標(biāo)簽名選擇器占业,請改用class選擇器。
- 避免使用后代選擇器:組件和引用組件的頁面中使用后代選擇器(.a .b)在一些極端情況下會有非預(yù)期的表現(xiàn)纯赎,如遇谦疾,請避免使用。
- 子元素選擇器只能用于view及子節(jié)點(diǎn):子元素選擇器(.a>.b)只能用于 view 組件與其子節(jié)點(diǎn)之間犬金,用于其他組件可能導(dǎo)致非預(yù)期的情況念恍。
- 繼承樣式:繼承樣式六剥,如 font 、 color 峰伙,會從組件外繼承到組件內(nèi)疗疟。
- app.wxss樣式組件對自定義組件無效:除繼承樣式外, app.wxss 中的樣式瞳氓、組件所在頁面的的樣式對自定義組件無效(除非更改組件樣式隔離選項(xiàng))秃嗜。
#a { } /* 在組件中不能使用 */
[a] { } /* 在組件中不能使用 */
button { } /* 在組件中不能使用 */
.a > .b { } /* 除非 .a 是 view 組件節(jié)點(diǎn),否則不一定會生效 */
除此以外顿膨,組件可以指定它所在節(jié)點(diǎn)的默認(rèn)樣式锅锨,使用 :host
選擇器(需要包含基礎(chǔ)庫 [1.7.2]。
/* 組件 custom-component.wxss */
:host {
color: yellow;
}
2恋沃、組件樣式隔離
默認(rèn)情況下必搞,自定義組件的樣式只受到自定義組件 wxss 的影響。除非以下兩種情況:
- app.wxss 或頁面的 wxss 中使用了標(biāo)簽名選擇器(或一些其他特殊選擇器)來直接指定樣式囊咏,這些選擇器會影響到頁面和全部組件恕洲。通常情況下這是不推薦的做法。
- 指定特殊的樣式隔離選項(xiàng) styleIsolation 梅割。
Component({
options: {
styleIsolation: 'isolated'
}
})
styleIsolation的選項(xiàng):
?isolated
表示啟用樣式隔離霜第,在自定義組件內(nèi)外,使用 class 指定的樣式將不會相互影響(一般情況下的默認(rèn)值)户辞;
?apply-shared
表示頁面 wxss 樣式將影響到自定義組件泌类,但自定義組件 wxss 中指定的樣式不會影響頁面;
?shared
表示頁面 wxss 樣式將影響到自定義組件底燎,自定義組件 wxss 中指定的樣式也會影響頁面和其他設(shè)置了 apply-shared 或 shared 的自定義組件刃榨。(這個選項(xiàng)在插件中不可用。)
使用后兩者時双仍,請務(wù)必注意組件間樣式的相互影響枢希。
如果這個Component 構(gòu)造器用于構(gòu)造頁面,則默認(rèn)值為 shared
朱沃,且還有以下幾個額外的樣式隔離選項(xiàng)可用:
-
page-isolated
表示在這個頁面禁用 app.wxss 苞轿,同時,頁面的 wxss 不會影響到其他自定義組件逗物; -
page-apply-shared
表示在這個頁面禁用 app.wxss 搬卒,同時,頁面 wxss 樣式不會影響到其他自定義組件敬察,但設(shè)為shared
的自定義組件會影響到頁面秀睛; -
page-shared
表示在這個頁面禁用 app.wxss ,同時莲祸,頁面 wxss 樣式會影響到其他設(shè)為apply-shared
或shared
的自定義組件蹂安,也會受到設(shè)為shared
的自定義組件的影響
在 Component 的 options
中設(shè)置addGlobalClass: true
椭迎。 這個選項(xiàng)等價于設(shè)置 styleIsolation: apply-shared
,但設(shè)置了 styleIsolation
選項(xiàng)后這個選項(xiàng)會失效田盈。
/* 組件 custom-component.js */
Component({
options: {
addGlobalClass: true,
}
})
3畜号、外部樣式類、引用頁面或父組件的樣式允瞧、虛擬化組件節(jié)點(diǎn)
參見官方文檔:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html
寫在最后:
如果文章中有錯誤或是表達(dá)不準(zhǔn)確的地方简软,歡迎大家評論中指正,以便我完善述暂。
文章我也會根據(jù)所學(xué)到新的知識不斷更新痹升。