引導(dǎo)
這是一個(gè)很簡(jiǎn)單的話(huà)題厌衔,但是你很難在搜索到一篇比較完整的介紹它的文章,或者說(shuō)單純的告訴你 ViewEncapsulation
的用法而已赡突,這在實(shí)際項(xiàng)目中遠(yuǎn)遠(yuǎn)不夠的紧索。
一袁辈、封裝模式
分別為:
-
Native
原先瀏覽器Shadow DOM行為。 -
Emulated
仿真模式珠漂,通過(guò)Angular來(lái)模擬類(lèi)似Shadow DOM的行為晚缩。 -
None
無(wú)任何封裝行為尾膊。
以上三種模式唯一的區(qū)別在于Shadow DOM,當(dāng)然其作用是讓組件的樣式只進(jìn)不出荞彼,換言之即組件內(nèi)的樣式不會(huì)影響到外部組件冈敛。有關(guān)于Shadow DOM更多的細(xì)節(jié)不在這里討論。
三者的表現(xiàn)形式
假定使用以下代碼:
@Component({
template: `<h1>test</h1>`,
styles: [`h1 { color: #f50; }`],
encapsulation: ViewEncapsulation.Native
})
在不同模式下產(chǎn)生的HTML&CSS風(fēng)格都不盡相同鸣皂,了解這些不一樣尤為重要抓谴。它們分別為:
Native:
#shadow-root (open)
<style>h1 { color: #f50; }</style>
<h1>test</h1>
Emulated:
<style>h1[_ngcontent-c0] { color: #f50; }</style>
<h1 _ngcontent-c0>test</h1>
None:
<style>h1 { color: #f50; }</style>
<h1>test</h1>
Native
&None
在內(nèi)容是一樣的,但其后者會(huì)影響至其他外部組件的h1
元素寞缝。
二癌压、組件樣式
組件樣式的封裝模式取決于我們對(duì) encapsulation
的配置,例如上面的示例荆陆。當(dāng)然你可以了在 main.ts
時(shí)為所有組件統(tǒng)一設(shè)定一種行的模式滩届,例如:
platformBrowserDynamic().bootstrapModule(AppModule, {
defaultEncapsulation: ViewEncapsulation.None
})
雖然三種模式都有不同的風(fēng)格,但對(duì)于一個(gè)組件而言慎宾,如果沒(méi)有一很合理的使用風(fēng)格在實(shí)際項(xiàng)目中會(huì)讓我們很頭疼丐吓,特別是當(dāng)項(xiàng)目中使用第三方組件庫(kù)(例如:ngx-bootstrap浅悉、ng-zorro-antd趟据、material2 等)時(shí),有時(shí)很容易受組件庫(kù)的影響抑或需要讓組件庫(kù)與業(yè)務(wù)組件樣式做一些微調(diào)時(shí)术健,了解一些細(xì)節(jié)非常重要汹碱。
例如一個(gè)用于渲染頁(yè)面標(biāo)頭名曰:app-header
組件,其中 <nz-breadcrumb>
面包屑 默認(rèn)情況下它會(huì)對(duì)最后一項(xiàng)進(jìn)行加粗荞估,但假設(shè)這不是我們希望的咳促,而應(yīng)該是一個(gè)不加粗和其他項(xiàng)一樣的文本:
<nz-breadcrumb>
<nz-breadcrumb-item>Home</nz-breadcrumb-item>
<nz-breadcrumb-item>Detail</nz-breadcrumb-item>
</nz-breadcrumb>
最終生成的HTML是這樣子:
<nz-breadcrumb _ngcontent-c1="" class="ant-breadcrumb">
<nz-breadcrumb-item _ngcontent-c1="">
<span class="ant-breadcrumb-link">
Home
</span>
<span class="ant-breadcrumb-separator">/</span></nz-breadcrumb-item>
<nz-breadcrumb-item _ngcontent-c1="">
<span class="ant-breadcrumb-link">
Detail
</span>
<span class="ant-breadcrumb-separator">/</span></nz-breadcrumb-item>
</nz-breadcrumb>
倘若你不假思索的在 app-header
組件的 styles
屬性中加上:
.ant-breadcrumb-link {
font-weight: normal;
}
正如你期望的那樣,可能不一定會(huì)有你想要的結(jié)果勘伺,亦或的結(jié)果可能會(huì)存在隱患跪腹。前面我說(shuō)過(guò)三種模式唯一的區(qū)別在于Shadow DOM,因此說(shuō)白了是兩種不同的結(jié)果飞醉。
若組件設(shè)定為 None
模式冲茸,而會(huì)生效,但只要 app-header
組件出現(xiàn)過(guò)一次在未來(lái)所有即使不再使用 app-header
組件的情況下所有的面包屑的最后一項(xiàng)都是是不加粗的缅帘,這便是我說(shuō)的隱患轴术。
反之,對(duì)于 Shadow 行為钦无,它會(huì)為 nz-breadcrumb
創(chuàng)建一個(gè)額外的屬性 _ngcontent-c1
來(lái)標(biāo)識(shí)(不管是 Native
逗栽、Emulated
本質(zhì)是一樣的)所設(shè)定的樣式僅限于 app-header
組件當(dāng)中。而 Angular 中即采用 :host
來(lái)表示組件自身失暂,所以前面的CSS樣式應(yīng)該變成這樣:
:host .ant-breadcrumb-link {
font-weight: normal;
}
最后生成的樣式會(huì)變成這樣:
[_nghost-c1] .ant-breadcrumb-link[_ngcontent-c1] {
font-weight: normal;
}
我認(rèn)為我們沒(méi)有必要去理解生成的標(biāo)識(shí)符是怎么樣彼宠,只需要知道 :host
表示組件自身鳄虱。
然而我們會(huì)發(fā)現(xiàn),對(duì)于第三方組件 nz-breadcrumb
組件而言凭峡,.ant-breadcrumb-link
是其組件內(nèi)部某個(gè)HTML元素的 class
而已贝或,且它有自己的一套組件封裝規(guī)則。但我們生成的CSS中包括了一個(gè)奇怪的字符 [_ngcontent-c1]
溃论,最終導(dǎo)致 app-header
組件樣式無(wú)法改變第三方組件 nz-breadcrumb
組件內(nèi)容的樣式圈澈。
這是很合理的,我的領(lǐng)地不可侵犯按价,Angular 組件本身即是 Web Component 標(biāo)準(zhǔn)的具體實(shí)現(xiàn)惭适。
難道我們沒(méi)有辦法侵犯第三方組件了嗎?好在 Angular 提供了一種對(duì)未來(lái)工具更好兼容性的命令 ::ng-deep
來(lái)強(qiáng)制樣式允許侵入子組件楼镐。
:host ::ng-deep .ant-breadcrumb-link {
font-weight: normal;
}
生成的CSS會(huì)是這樣:
[_nghost-c1] .ant-breadcrumb-link {
font-weight: normal;
}
最終這個(gè)不加粗的效果只會(huì)在 app-header
組件內(nèi)部有效癞志。
總結(jié)
熟悉 :host
、::ng-deep
組合用法對(duì)組件樣式的構(gòu)建很關(guān)鍵框产,Angular 組件有自己的業(yè)務(wù)邏輯凄杯、樣式、HTML模板它們是構(gòu)建一個(gè) Web Component 的基礎(chǔ)技術(shù)核心秉宿。
希望此篇能幫助大家更好理解組件樣式戒突。
Happy coding!