
前言
在上一節(jié)我們了解了如何給自定義組件設(shè)置樣式,當(dāng)時(shí)是將自定義標(biāo)簽的樣式設(shè)置在主 DOM 中的:
<style>
my-card {
display: block;
margin: 20px;
width: 200px;
height: 200px;
border: 3px solid #000;
}
</style>
<my-card></my-card>
雖然實(shí)現(xiàn)了樣式設(shè)置的目的,但是卻存在一個(gè)弊端:自定義標(biāo)簽的樣式被寫(xiě)死了,不夠靈活。
如果能夠在自定義組件內(nèi)部控制自定義標(biāo)簽的樣式,那樣的話會(huì)相對(duì)靈活,而且也算是實(shí)現(xiàn)了”封裝、相互隔離“的組件原則。今天,我們就來(lái)學(xué)習(xí)一下如何在自定義組件內(nèi)部實(shí)現(xiàn)自定義標(biāo)簽的樣式控制。
在正文開(kāi)始之前,我們?cè)購(gòu)?fù)習(xí)一下 Shadow DOM 的整體結(jié)構(gòu):

Shadow DOM 的 CSS 選擇器
今天的重點(diǎn)是認(rèn)識(shí)與 Shadow DOM 相關(guān)的幾個(gè)選擇器。
:host 偽類選擇器
選取內(nèi)部使用該部分 CSS 的 Shadow host 元素,其實(shí)也就是自定義標(biāo)簽元素。用法如下:
:host {
display: block;
margin: 20px;
width: 200px;
height: 200px;
border: 3px solid #000;
}
注意::host 選擇器只在 Shadow DOM 中使用才有效果。
比如:

另外,可以使用 :host 子選擇器 的形式來(lái)給 Shadow Host 的子元素設(shè)置樣式,比如:

:host 偽類選擇器的兼容性如下:

:host()偽類函數(shù)
:host() 的作用是獲取給定選擇器的 Shadow Host。比如下面的代碼:
<my-card class="my-card"></my-card>
<my-card></my-card>
<script>
class MyCard extends HTMLElement {
constructor () {
super();
this.shadow = this.attachShadow({mode: "open"});
let styleEle = document.createElement("style");
styleEle.textContent = `
:host(.my-card){
display: block;
margin: 20px;
width: 200px;
height: 200px;
border: 3px solid #000;
}
:host .card-header{
border: 2px solid red;
padding:10px;
background-color: yellow;
font-size: 16px;
font-weight: bold;
}
`;
this.shadow.appendChild(styleEle);
let headerEle = document.createElement("div");
headerEle.className = "card-header";
headerEle.innerText = "My Card";
this.shadow.appendChild(headerEle);
}
}
window.customElements.define("my-card", MyCard);
</script>
:host(.my-card) 只會(huì)選擇類名為 my-card 的自定義元素, 且它后面也可以跟子選擇器來(lái)選擇自己跟節(jié)點(diǎn)下的子元素。
需要注意的是::host() 的參數(shù)是必傳的,否則選擇器函數(shù)失效,比如:

:host() 偽類函數(shù)的兼容性如下:

:host-context()偽類函數(shù)
用來(lái)選擇特定祖先內(nèi)部的自定義元素,祖先元素選擇器通過(guò)參數(shù)傳入。比如以下代碼:
<div id="container">
<my-card></my-card>
</div>
<my-card></my-card>
<script>
class MyCard extends HTMLElement {
constructor () {
super();
this.shadow = this.attachShadow({mode: "open"});
let styleEle = document.createElement("style");
styleEle.textContent = `
:host-context(#container){
display: block;
margin: 20px;
width: 200px;
height: 200px;
border: 3px solid #000;
}
:host .card-header{
border: 2px solid red;
padding:10px;
background-color: yellow;
font-size: 16px;
font-weight: bold;
}
`;
this.shadow.appendChild(styleEle);
let headerEle = document.createElement("div");
headerEle.className = "card-header";
headerEle.innerText = "My Card";
this.shadow.appendChild(headerEle);
}
}
window.customElements.define("my-card", MyCard);
</script>
:host-context(#container) 只會(huì)對(duì) id 為 container 元素下的自定義元素生效,效果如下:

注意:這里的參數(shù)也是必傳的,否則整個(gè)選擇器函數(shù)不生效。
其兼容性如下:

:host 和 :host()共存的必要性
看完上面的介紹后,不少人可能會(huì)有這樣一個(gè)疑惑::host(.my-card){} 不是可以直接用 :host.my-card{} 代替?
答案是不可以?。?!,因?yàn)椋?code>:host.my-card 實(shí)質(zhì)上的意思是找 .my-card (Shadow root)的 :host(Shadow Host) ,這 Shadow DOM 的從結(jié)構(gòu)上來(lái)說(shuō)就已經(jīng)互相矛盾了。
總結(jié)
以上就是關(guān)于 Shadow Host 的 CSS 選擇器內(nèi)容,總結(jié)一下:
-
:host范圍最大,匹配所有的自定義元素實(shí)例; -
:host()只選擇自身包含特定選擇器的自定義元素; -
:host-context()選擇擁有特定選擇器父元素的自定義元素。
~
~ 本文完,感謝閱讀!
~
學(xué)習(xí)有趣的知識(shí),結(jié)識(shí)有趣的朋友,塑造有趣的靈魂!