在介紹 ViewEncapsulation
之前寂嘉,我們先來介紹一下 Web Components 標(biāo)準(zhǔn)瀑凝。
Web Components
近年來,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)化的非侵入的方式封裝一個組件,每個組件能組織好它自身的 HTML 結(jié)構(gòu)、CSS 樣式疏唾、JavaScript 代碼蓄氧,并且不會干擾頁面上的其他元素。
Web Components 由以下四種技術(shù)組成:
- Custom Elements - 自定義元素
- HTML Templates - HTML模板
- Shadow DOM - 影子DOM
- HTML Imports - HTML導(dǎo)入
因為 Shadow DOM 與 Angular ViewEncapsulation 相關(guān)荸实, 所以這篇文章我們主要介紹 Shadow DOM 相關(guān)的內(nèi)容匀们。
Shadow DOM
<!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();
// 影子根作為影子樹的第一個節(jié)點,其他的節(jié)點比如p節(jié)點都是它的子節(jié)點准给。
shadowRoot.innerHTML = '<p class="shadowroot_son">我在 Shadow Host內(nèi)</p>';
</script>
</body>
<html>
以上代碼成功運行后泄朴,如下圖:
我們發(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
ViewEncapsulation 允許設(shè)置三個可選的值:
- ViewEncapsulation.Emulated - 無 Shadow DOM,但是通過 Angular 提供的樣式包裝機制來封裝組件叁扫,使得組件的樣式不受外部影響三妈。這是 Angular 的默認設(shè)置。
- ViewEncapsulation.Native - 使用原生的 Shadow DOM 特性
- ViewEncapsulation.None - 無 Shadow DOM莫绣,并且也無樣式包裝
ViewEncapsulation 枚舉定義:
export enum ViewEncapsulation {
Emulated, // 默認值
Native,
None
}
ViewEncapsulation.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';
}
運行后的結(jié)果:
ViewEncapsulation.None 設(shè)置的結(jié)果是沒有 Shadow DOM畴蒲,并且所有的樣式都應(yīng)用到整個 document,換句話說对室,組件的樣式會受外界影響模燥,可能被覆蓋掉。
ViewEncapsulation.Emulated
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'my-app',
...,
encapsulation: ViewEncapsulation.Emulated // None | Emulated | Native
})
export class AppComponent {
name: string = 'Semlinker';
}
運行后的結(jié)果:
ViewEncapsulation.Emulated 設(shè)置的結(jié)果是沒有 Shadow DOM掩宜,但是通過 Angular 提供的樣式包裝機制來封裝組件蔫骂,使得組件的樣式不受外部影響。雖然樣式仍然是應(yīng)用到整個 document牺汤,但 Angular 為 .greet
類創(chuàng)建了一個 [_ngcontent-cmy-0]
選擇器辽旋。可以看出檐迟,我們?yōu)榻M件定義的樣式戴已,被 Angular 修改了。其中的 _nghost-cmy-*
和 _ngcontent-cmy-*
用來實現(xiàn)局部的樣式锅减。
ViewEncapsulation.Native
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'my-app',
...,
encapsulation: ViewEncapsulation.Native // None | Emulated | Native
})
export class AppComponent {
name: string = 'Semlinker';
}
運行后的結(jié)果:
ViewEncapsulation.Native 設(shè)置的結(jié)果是使用原生的 Shadow DOM 特性。Angular 會把組件按照瀏覽器支持的 Shadow DOM 形式渲染伐坏,渲染結(jié)果如上圖所示怔匣。