Web Component 是一種 W3C標準 支持的 組件化方案,經過它,咱們能夠編寫可複用的 組件,同時,咱們也能夠對本身的組件作更精細化的控制。正如 PWA 同樣,他並不是一項單一的技術,而是由三項技術組成:javascript
下面,咱們從一個簡單的例子來入手。css
咱們準備編寫一個 TextReverse
組件,TextReverse
只有一個很簡單的功能,就是把傳入的 字符串顛倒顯示。html
例如: <text-reverse text='123'></text-reverse>
將會顯示 321
。java
第一步,咱們須要 定義 這個自定義組件。瀏覽器
class TextReverse extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
const text = this.getAttribute('text') || '';
const wrapper = document.createElement('span');
wrapper.textContent = text.split('').reverse().join('');
shadowRoot.appendChild(wrapper);
}
}
複製代碼
定義組件的方式也十分簡單,咱們只須要 繼承一下 HTMLElement
,而後在 構造函數 中編寫本身的 初始化邏輯 就能夠了。app
初始化過程當中,咱們首先 建立了一個 shadowRoot
,這個至關因而咱們整個組件的一個 根結點。框架
緊接着,咱們獲取到自身的 text
屬性,而且將其 倒置 放入新建立的 span
元素中。dom
最後,咱們把帶有 text
的 span
塞入 shadowRoot
。函數
定義完成以後,咱們要告知一下系統,也就是 組件註冊。組件化
customElements.define(
'text-reverse',
TextReverse
)
複製代碼
這裏有一個小細節,就是咱們註冊的名字必須是帶短橫線的。
註冊完成以後就能夠正式使用啦。
<text-reverse text='12345'></text-reverse>
複製代碼
上面的例子中,咱們用到了 shadow root,他承載着咱們組件全部的內容。而他也是 Web Component 核心技術。
咱們都知道 Dom 其實就是一棵樹,而咱們的組件則是樹上的一個節點。咱們能夠稱組件節點爲 shadow host。
shadow host 中含有一顆與外界隔離的 dom 樹,咱們稱之爲 shadow tree。shadow tree 中的內容不會影響到外界。Shadow Root 則是這一課shadow tree 的根節點。
結構如圖所示:
shadow dom 一大亮點就是樣式隔離。咱們能夠給以前的例子加上樣式。
class TextReverse extends HTMLElement {
constructor() {
super();
// ...
const style = document.createElement('style');
style.textContent = `* { background: red; }`
shadowRoot.appendChild(style);
// ...
}
}
複製代碼
咱們給全部元素添加一個紅的背景色。可是,結果只有組件內的元素背景色受到了影響。這種樣式隔離的特性很好地避免了不一樣組件之間的樣式干擾。
在上面的例子中,咱們採用代碼的方式來建立修改節點。相較於 React 的 Jsx 和 Vue 的模版,這種方法比較低效。因此,咱們可使用 Template 來解決這問題。
<template id='text-reverse'>
<style> *{ background: red; } </style>
<span id='text'></span>
</template>
複製代碼
class TextReverse extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
const text = this.getAttribute('text') || '';
const template = document.getElementById('text-reverse').content.cloneNode(true);
template.getElementById('text').textContent = text.split('').reverse().join('');
shadowRoot.appendChild(template);
}
}
複製代碼
咱們在 html 中定義了一個 template,而後,就和操做普通元素同樣獲取到 template 節點,而後深拷貝一份節點內容。最後直接操做這個節點。
和 Vue 的 Slot 類似,Slot 賦予了組件更高的可擴展性。經過 Slot,咱們能夠給組件傳入更多的自定義內容。
在上面的例子中,咱們給組件添加一個自定義的標題。
<text-reverse text='12345'>
<span slot='title'>text reverse</span>
</text-reverse>
<template id='text-reverse'>
<h1><slot name='title'>default title</slot></h1>
<span id='text'></span>
</template>
複製代碼
模版中,咱們定義一個 slot 元素,命名爲 title,而且設置一個無內容時的默認值 default title。 使用的時候,咱們在元素中添加一個 slot 屬性來與模版中的 slot 相匹配。
至今,咱們都是徹底自定義組件內容,假如咱們想擴展示有系統元素,那就須要定義一個 內置自定義元素。 咱們來用一個屏蔽數字的 p 元素來講明。
class PFilter extends HTMLParagraphElement {
constructor() {
super();
const textContent = this.textContent;
this.textContent = textContent.replace(/\d/g, '*');
}
}
customElements.define(
'p-filter',
PFilter,
{
extends: 'p'
}
)
複製代碼
咱們這邊再也不是繼承 HTMLElement
,而是繼承須要擴展的 p節點 HTMLParagraphElement
。
<p is='p-filter'>個人手機號是:10086</p>
複製代碼
不一樣於獨立自定義組件,咱們仍是須要用原有元素名去聲明,而且在 is
屬性中填寫咱們的組件名。
和大多數框架同樣,Web Component 也含有許多控制組件生命週期的方法。
咱們只需在定義組件的類中聲明對應的方法便可。attributeChangedCallback
相對與別的屬性比較特別,他須要 搭配 observedAttributes
使用。
class TextReverse extends HTMLElement {
//...
static get observedAttributes () {
return ['text'];
}
attributeChangedCallback () {
const text = this.getAttribute('text') || '';
this.shadowRoot.getElementById('text').textContent = text.split('').reverse().join('');
}
}
複製代碼
咱們在 observedAttributes
靜態方法中添加須要監聽的屬性值。而後,在 text
改變的時候,觸發 attributeChangedCallback
方法來更新 text
的值。
Web Component 的功能十分強大,相較於 React,Vue等框架,他天生自帶樣式隔離,而且最主要的是擁有瀏覽器的原生支持。不過,想要達到工程開發標準 的話,他還有一段很長很長的路要走。