在介紹 ViewEncapsulation
之前,我們先來介紹一下 Web Components 標(biāo)準(zhǔn)。
近年來,Web 開發(fā)者們通過插件或者模塊的形式在網(wǎng)上分享自己的代碼,便于其他開發(fā)者們復(fù)用這些優(yōu)秀的代碼。同樣的故事不斷發(fā)生,人們不斷的復(fù)用 JavaScript 文件,然后是 CSS 文件,當(dāng)然還有 HTML 片段。但是你又必須祈禱這些引入的代碼不會影響到你的網(wǎng)站或者 Web App。
Web Components 是解決這類問題最好的良藥,它通過一種標(biāo)準(zhǔn)化的非侵入的方式封裝一個(gè)組件,每個(gè)組件能組織好它自身的 HTML 結(jié)構(gòu)、CSS 樣式、JavaScript 代碼,并且不會干擾頁面上的其他元素。
Web Components 由以下四種技術(shù)組成:
因?yàn)?Shadow DOM 與 Angular ViewEncapsulation 相關(guān), 所以這篇文章我們主要介紹 Shadow DOM 相關(guān)的內(nèi)容。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Shadow DOM</title>
<style type="text/css">
.shadowroot_son {
color: #f00;
}
</style>
</head>
<body>
<p class="shadowroot_son">我不在 Shadow Host內(nèi)</p>
<div class="shadowhost">Hello, world!</div>
<script>
// 影子宿主(shadow host)
var shadowHost = document.querySelector('.shadowhost');
// 創(chuàng)建影子根(shadow root)
var shadowRoot = shadowHost.createShadowRoot();
// 影子根作為影子樹的第一個(gè)節(jié)點(diǎn),其他的節(jié)點(diǎn)比如p節(jié)點(diǎn)都是它的子節(jié)點(diǎn)。
shadowRoot.innerHTML = '<p class="shadowroot_son">我在 Shadow Host內(nèi)</p>';
</script>
</body>
<html>
以上代碼成功運(yùn)行后,如下圖:
我們發(fā)現(xiàn)在 #shadow-root
中的元素,不受我們外界定義的 CSS shadowroot_son
類影響。因此我們可以利用 Shadow DOM 來封裝我們自定義的 HTML 標(biāo)簽、CSS 樣式和 JavaScript 代碼。需要注意的是 Shadow DOM 兼容性還不是很好,具體請參考 - Can I Use Shadow DOM 。
接下來我們開始介紹 Angular ViewEncapsulation Modes:
ViewEncapsulation 允許設(shè)置三個(gè)可選的值:
ViewEncapsulation 枚舉定義:
export enum ViewEncapsulation {
Emulated, // 默認(rèn)值
Native,
None
}
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<h4>Welcome to Angular World</h4>
<p class="greet">Hello {{name}}</p>
`,
styles: [`
.greet {
background: #369;
color: white;
}
`],
encapsulation: ViewEncapsulation.None // None | Emulated | Native
})
export class AppComponent {
name: string = 'Semlinker';
}
運(yùn)行后的結(jié)果:
ViewEncapsulation.None 設(shè)置的結(jié)果是沒有 Shadow DOM,并且所有的樣式都應(yīng)用到整個(gè) document,換句話說,組件的樣式會受外界影響,可能被覆蓋掉。
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'my-app',
...,
encapsulation: ViewEncapsulation.Emulated // None | Emulated | Native
})
export class AppComponent {
name: string = 'Semlinker';
}
運(yùn)行后的結(jié)果:
ViewEncapsulation.Emulated 設(shè)置的結(jié)果是沒有 Shadow DOM,但是通過 Angular 提供的樣式包裝機(jī)制來封裝組件,使得組件的樣式不受外部影響。雖然樣式仍然是應(yīng)用到整個(gè) document,但 Angular 為 .greet
類創(chuàng)建了一個(gè) [_ngcontent-cmy-0]
選擇器??梢钥闯?,我們?yōu)榻M件定義的樣式,被 Angular 修改了。其中的 _nghost-cmy-*
和 _ngcontent-cmy-*
用來實(shí)現(xiàn)局部的樣式。
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'my-app',
...,
encapsulation: ViewEncapsulation.Native // None | Emulated | Native
})
export class AppComponent {
name: string = 'Semlinker';
}
運(yùn)行后的結(jié)果:
ViewEncapsulation.Native 設(shè)置的結(jié)果是使用原生的 Shadow DOM 特性。Angular 會把組件按照瀏覽器支持的 Shadow DOM 形式渲染,渲染結(jié)果如上圖所示。
更多建議: