# 組件模板和樣式
類(lèi)似于頁(yè)面,自定義組件擁有自己的 wxml 模板和 wxss 樣式。
# 組件模板
組件模板的寫(xiě)法與頁(yè)面模板相同。組件模板與組件數(shù)據(jù)結(jié)合后生成的節(jié)點(diǎn)樹(shù),將被插入到組件的引用位置上。
在組件模板中可以提供一個(gè) <slot> 節(jié)點(diǎn),用于承載組件引用時(shí)提供的子節(jié)點(diǎn)。
代碼示例:
<!-- 組件模板 -->
<view class="wrapper">
<view>這里是組件的內(nèi)部節(jié)點(diǎn)</view>
<slot></slot>
</view>
<!-- 引用組件的頁(yè)面模板 -->
<view>
<component-tag-name>
<!-- 這部分內(nèi)容將被放置在組件 <slot> 的位置上 -->
<view>這里是插入到組件slot中的內(nèi)容</view>
</component-tag-name>
</view>
注意,在模板中引用到的自定義組件及其對(duì)應(yīng)的節(jié)點(diǎn)名需要在 json 文件中顯式定義,否則會(huì)被當(dāng)作一個(gè)無(wú)意義的節(jié)點(diǎn)。除此以外,節(jié)點(diǎn)名也可以被聲明為抽象節(jié)點(diǎn)。
# 模板數(shù)據(jù)綁定
與普通的 WXML 模板類(lèi)似,可以使用數(shù)據(jù)綁定,這樣就可以向子組件的屬性傳遞動(dòng)態(tài)數(shù)據(jù)。
代碼示例:
<!-- 引用組件的頁(yè)面模板 -->
<view>
<component-tag-name prop-a="{{dataFieldA}}" prop-b="{{dataFieldB}}">
<!-- 這部分內(nèi)容將被放置在組件 <slot> 的位置上 -->
<view>這里是插入到組件slot中的內(nèi)容</view>
</component-tag-name>
</view>
在以上例子中,組件的屬性 propA 和 propB 將收到頁(yè)面?zhèn)鬟f的數(shù)據(jù)。頁(yè)面可以通過(guò) setData 來(lái)改變綁定的數(shù)據(jù)字段。
注意:這樣的數(shù)據(jù)綁定只能傳遞 JSON 兼容數(shù)據(jù)。自基礎(chǔ)庫(kù)版本 2.0.9 開(kāi)始,還可以在數(shù)據(jù)中包含函數(shù)(但這些函數(shù)不能在 WXML 中直接調(diào)用,只能傳遞給子組件)。
# 組件 wxml 的 slot
在組件的 wxml 中可以包含 slot 節(jié)點(diǎn),用于承載組件使用者提供的 wxml 結(jié)構(gòu)。
默認(rèn)情況下,一個(gè)組件的 wxml 中只能有一個(gè) slot 。需要使用多 slot 時(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>
# 組件樣式
組件對(duì)應(yīng) wxss 文件的樣式,只對(duì)組件wxml內(nèi)的節(jié)點(diǎn)生效。編寫(xiě)組件樣式時(shí),需要注意以下幾點(diǎn):
- 組件和引用組件的頁(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ú)效(除非更改組件樣式隔離選項(xiàng))。
#a { } /* 在組件中不能使用 */
[a] { } /* 在組件中不能使用 */
button { } /* 在組件中不能使用 */
.a > .b { } /* 除非 .a 是 view 組件節(jié)點(diǎn),否則不一定會(huì)生效 */
除此以外,組件可以指定它所在節(jié)點(diǎn)的默認(rèn)樣式,使用 :host 選擇器(需要包含基礎(chǔ)庫(kù) 1.7.2 或更高版本的開(kāi)發(fā)者工具支持)。
代碼示例:
/* 組件 custom-component.wxss */
:host {
color: yellow;
}
<!-- 頁(yè)面的 WXML -->
<custom-component>這段文本是黃色的</custom-component>
# 組件樣式隔離
默認(rèn)情況下,自定義組件的樣式只受到自定義組件 wxss 的影響。除非以下兩種情況:
- 指定特殊的樣式隔離選項(xiàng)
styleIsolation。 - webview 渲染下,在
app.wxss或頁(yè)面的wxss中使用標(biāo)簽名選擇器(或一些其他特殊選擇器)來(lái)直接指定樣式會(huì)影響到頁(yè)面和全部組件。通常情況下這是不推薦的做法。
{
"styleIsolation": "isolated"
}
自定義組件 JSON 中的 styleIsolation 選項(xiàng)從基礎(chǔ)庫(kù)版本 2.10.1 開(kāi)始支持。它支持以下取值:
isolated表示啟用樣式隔離,在自定義組件內(nèi)外,使用 class 指定的樣式將不會(huì)相互影響(一般情況下的默認(rèn)值);apply-shared表示頁(yè)面 wxss 樣式將影響到自定義組件,但自定義組件 wxss 中指定的樣式不會(huì)影響頁(yè)面;shared表示頁(yè)面 wxss 樣式將影響到自定義組件,自定義組件 wxss 中指定的樣式也會(huì)影響頁(yè)面和其他設(shè)置了apply-shared或shared的自定義組件。(這個(gè)選項(xiàng)在插件中不可用。)
使用后兩者時(shí),請(qǐng)務(wù)必注意組件間樣式的相互影響。
如果這個(gè) Component 構(gòu)造器用于構(gòu)造頁(yè)面 ,則默認(rèn)值為 shared ,且還有以下幾個(gè)額外的樣式隔離選項(xiàng)可用:
page-isolated表示在這個(gè)頁(yè)面禁用 app.wxss ,同時(shí),頁(yè)面的 wxss 不會(huì)影響到其他自定義組件;page-apply-shared表示在這個(gè)頁(yè)面禁用 app.wxss ,同時(shí),頁(yè)面 wxss 樣式不會(huì)影響到其他自定義組件,但設(shè)為shared的自定義組件會(huì)影響到頁(yè)面;page-shared表示在這個(gè)頁(yè)面禁用 app.wxss ,同時(shí),頁(yè)面 wxss 樣式會(huì)影響到其他設(shè)為apply-shared或shared的自定義組件,也會(huì)受到設(shè)為shared的自定義組件的影響。
其他不再推薦的配置方式
從小程序基礎(chǔ)庫(kù)版本 2.6.5 開(kāi)始,styleIsolation 可以在 JS 文件的 options 中配置。例如:
Component({
options: {
styleIsolation: 'isolated'
}
})
此外,小程序基礎(chǔ)庫(kù)版本 2.2.3 以上支持 addGlobalClass 選項(xiàng),即在 Component 的 options 中設(shè)置 addGlobalClass: true 。
這個(gè)選項(xiàng)等價(jià)于設(shè)置 styleIsolation: apply-shared ,但設(shè)置了 styleIsolation 選項(xiàng)后這個(gè)選項(xiàng)會(huì)失效。
代碼示例:
/* 組件 custom-component.js */
Component({
options: {
addGlobalClass: true,
}
})
<!-- 組件 custom-component.wxml -->
<text class="red-text">這段文本的顏色由 `app.wxss` 和頁(yè)面 `wxss` 中的樣式定義來(lái)決定</text>
/* app.wxss */
.red-text {
color: red;
}
# 外部樣式類(lèi)
基礎(chǔ)庫(kù) 1.9.90 開(kāi)始支持,低版本需做兼容處理。
有時(shí),組件希望接受外部傳入的樣式類(lèi)。此時(shí)可以在 Component 中用 externalClasses 定義段定義若干個(gè)外部樣式類(lèi)。
這個(gè)特性可以用于實(shí)現(xiàn)類(lèi)似于 view 組件的 hover-class 屬性:頁(yè)面可以提供一個(gè)樣式類(lèi),賦予 view 的 hover-class ,這個(gè)樣式類(lèi)本身寫(xiě)在頁(yè)面中而非 view 組件的實(shí)現(xiàn)中。
注意:在同一個(gè)節(jié)點(diǎn)上使用普通樣式類(lèi)和外部樣式類(lèi)時(shí),兩個(gè)類(lèi)的優(yōu)先級(jí)是未定義的,因此最好避免這種情況。
代碼示例:
/* 組件 custom-component.js */
Component({
externalClasses: ['my-class']
})
<!-- 組件 custom-component.wxml -->
<custom-component class="my-class">這段文本的顏色由組件外的 class 決定</custom-component>
這樣,組件的使用者可以指定這個(gè)樣式類(lèi)對(duì)應(yīng)的 class ,就像使用普通屬性一樣。在 2.7.1 之后,可以指定多個(gè)對(duì)應(yīng)的 class 。
代碼示例:
<!-- 頁(yè)面的 WXML -->
<custom-component my-class="red-text" />
<custom-component my-class="large-text" />
<!-- 以下寫(xiě)法需要基礎(chǔ)庫(kù)版本 2.7.1 以上 -->
<custom-component my-class="red-text large-text" />
.red-text {
color: red;
}
.large-text {
font-size: 1.5em;
}
# 引用頁(yè)面或父組件的樣式
基礎(chǔ)庫(kù) 2.9.2 開(kāi)始支持,低版本需做兼容處理。
即使啟用了樣式隔離 isolated ,組件仍然可以在局部引用組件所在頁(yè)面的樣式或父組件的樣式。
例如,如果在頁(yè)面 wxss 中定義了:
.blue-text {
color: blue;
}
在這個(gè)組件中可以使用 ~ 來(lái)引用這個(gè)類(lèi)的樣式:
<view class="~blue-text"> 這段文本是藍(lán)色的 </view>
如果在一個(gè)組件的父組件 wxss 中定義了:
.red-text {
color: red;
}
在這個(gè)組件中可以使用 ^ 來(lái)引用這個(gè)類(lèi)的樣式:
<view class="^red-text"> 這段文本是紅色的 </view>
也可以連續(xù)使用多個(gè) ^ 來(lái)引用祖先組件中的樣式。
注意:如果組件是比較獨(dú)立、通用的組件,請(qǐng)優(yōu)先使用外部樣式類(lèi)的方式,而非直接引用父組件或頁(yè)面的樣式。
# 虛擬化組件節(jié)點(diǎn)
基礎(chǔ)庫(kù) 2.11.2 開(kāi)始支持,低版本需做兼容處理。
默認(rèn)情況下,自定義組件本身的那個(gè)節(jié)點(diǎn)是一個(gè)“普通”的節(jié)點(diǎn),使用時(shí)可以在這個(gè)節(jié)點(diǎn)上設(shè)置 class style 、動(dòng)畫(huà)、 flex 布局等,就如同普通的 view 組件節(jié)點(diǎn)一樣。
<!-- 頁(yè)面的 WXML -->
<view style="display: flex">
<!-- 默認(rèn)情況下,這是一個(gè)普通的節(jié)點(diǎn) -->
<custom-component style="color: blue; flex: 1">藍(lán)色、滿(mǎn)寬的</custom-component>
</view>
但有些時(shí)候,自定義組件并不希望這個(gè)節(jié)點(diǎn)本身可以設(shè)置樣式、響應(yīng) flex 布局等,而是希望自定義組件內(nèi)部的第一層節(jié)點(diǎn)能夠響應(yīng) flex 布局或者樣式由自定義組件本身完全決定。
這種情況下,可以將這個(gè)自定義組件設(shè)置為“虛擬的”:
Component({
options: {
virtualHost: true
},
properties: {
style: { // 定義 style 屬性可以拿到 style 屬性上設(shè)置的值
type: String,
}
},
externalClasses: ['class'], // 可以將 class 設(shè)為 externalClasses
})
這樣,可以將 flex 放入自定義組件內(nèi):
<!-- 頁(yè)面的 WXML -->
<view style="display: flex">
<!-- 如果設(shè)置了 virtualHost ,節(jié)點(diǎn)上的樣式將失效 -->
<custom-component style="color: blue">不是藍(lán)色的</custom-component>
</view>
<!-- custom-component.wxml -->
<view style="flex: 1">
滿(mǎn)寬的
<slot></slot>
</view>
需要注意的是,自定義組件節(jié)點(diǎn)上的 class style 和動(dòng)畫(huà)將不再生效,但仍可以:
- 將 style 定義成
properties屬性來(lái)獲取 style 上設(shè)置的值; - 將 class 定義成
externalClasses外部樣式類(lèi)使得自定義組件 wxml 可以使用 class 值。
代碼示例: