在開發(fā) Angular 組件的過程中,我們習(xí)慣把組件的樣式寫在對(duì)應(yīng)的 css 文件中,但是一直不了解 Angular 是怎樣做到樣式隔離的,比如在 A 組件中寫了 h1 { color: red }
,這個(gè)樣式只會(huì)在 A 組件中生效,而不會(huì)影響到其他的組件。為了探究原理,就有了這篇文章,以下內(nèi)容基于 Angular CLI 10.1.1 版本創(chuàng)建。
組件樣式工作原理
探索
首先用 Angular CLI 創(chuàng)建一個(gè)新的 Angular 項(xiàng)目,刪除 app.component.html
中的所有內(nèi)容,替換成如下內(nèi)容:
<h1>App Component</h1> <button class="red-button">Button</button>
在 app.component.css
中添加如下內(nèi)容:
.red-button { color: red; }
運(yùn)行時(shí)有如下 html 代碼:
<app-root _nghost-ydo-c11="" ng-version="10.1.1"> <h2 _ngcontent-ydo-c11="">App component</h2> <button _ngcontent-ydo-c11="" class="red-button">Button</button> </app-root>
可以看到在在 app-root
元素上有一個(gè)名為 _nghost-ydo-c11
的屬性(property),app-root
里面的兩個(gè)元素都有一個(gè)名為 _ngcontent-ydo-c11
的屬性。
那么這些屬性是用來(lái)做什么的呢?
為了更好的理解,我們先創(chuàng)建一個(gè)獨(dú)立的組件,新建文件 blue-button.component.ts
,內(nèi)容如下:
import { Component } from '@angular/core'; @Component({ selector: 'app-blue-button', template: ` <h2>Blue button component</h2> <button class="blue-button">Button</button> `, styles: [` .blue-button { background: blue; } `] }) export class BlueButtonComponent {}
放到 app.component.html
中運(yùn)行后,會(huì)看到如下 html 代碼:
可以看到 app-blue-button
中也有一個(gè)以 _nghost-xxx
開頭的屬性,還有一個(gè)和 app-root
中其他元素相同的屬性。而在組件里面的兩個(gè)元素都有名為 _ngcontent-yke-c11
的屬性。
由于每次運(yùn)行,Angular 生成的屬性字符串都是隨機(jī)的,所以后面的代碼如果出現(xiàn)了類似的屬性都是按照這個(gè)截圖對(duì)應(yīng)的。
總結(jié)
通過觀察我們可以總結(jié)出:
- 每個(gè)組件的宿主元素都會(huì)被分配一個(gè)唯一的屬性,具體取決于組件的處理順序,在例子中就是
_nghost_xxx
- 每個(gè)組件模板中的每個(gè)元素還會(huì)被分配一個(gè)該組件特有的屬性,在例子中就是
_ngcontent_xxx
那么這些屬性是怎樣用于樣式隔離的呢?
這些屬性可以和 CSS 結(jié)合起來(lái),比如當(dāng)我們查看例子中藍(lán)色按鈕的樣式時(shí),會(huì)看到這樣的 css:
.blue-button[_ngcontent-yke-c11] { background: blue; }
可以看出,Angular 通過這種方式使 blue-button
類只能應(yīng)用于有這個(gè)屬性的元素上,而不會(huì)影響到其他組件中的元素。
知道了 Angular 對(duì)樣式隔離的行為,那么 Angular 又是如何做到這些的呢?
在應(yīng)用啟動(dòng)時(shí),Angular 將通過 styles 或 styleUrls 組件屬性來(lái)查看哪些樣式與哪些組件相關(guān)聯(lián)。之后Angular 會(huì)將這些樣式和該組件中元素特有的屬性應(yīng)用到一起,將生成的 css 代碼包裹在一個(gè) style 標(biāo)簽中并放到 header 里。