[譯] 組件化開發利器:Web Components標準

收藏待读

https://juejin.im/post/5c4a972b6fb9a049a7122eb7

自從第一個動態的 DHTML 光標拖拽的誕生,以及「本周網站」的徽章為網站增色,可復用代碼對 web 開發者極具誘惑力。但是在自己的網站中引入三方 UI 組件一直是一個比較頭疼的事情。

引入別人造好的輪子會帶來很多 javascript 和 css衝突,想想那些可怕的 !important 吧。使用現代前端框架比如React可能會好一些,但是為了為了重用一些組件而引入一個框架顯然是有些笨重。 HTML5 把一些常用的組件引入 web 標準,像 ,但是,為每個常用Web UI庫添加新標準標籤並不是一個可持續維護的方式。

這時,一些 web 標準草案就應運而生了。每個標準有其獨立的功能,但是把他們組合在一起,就能解決之前不能用原生方案解決的問題,並且它們非常難偽造,因為自定義 HTML 組件可以像傳統 HTML 標籤一樣使用。這些組件把複雜的實現封裝在內部,就像富文本編輯器和視頻播放器一樣。

標準發展

整體來說,這組標準就是Web Components。在2018年前端組件化並不是什麼新鮮事物。的確,從2014年開始,chrome一直以這樣或那樣的方式實現這些標準,其他瀏覽器也有相應的polyfills。

在標準委員會工作了一段時間之後,Web Components 標準從早期的形式(現稱為version 0版本)演變成了更成熟的version 1版本,並且被主流瀏覽器實現。Firefox63 對此增加了兩個支持:Custom Elements、shadow DOM。現在一起來看看怎麼扮演 HTML 的發明家吧!

Web Components已經存在了一段時間,相關資源比較多。本文只作為初級讀物,介紹一些列的新性能和資源,如果你想了解更多(你也應該了解更多),請移步MDN Web Docs 和Google Developers。

自定義 HTML 標籤需要瀏覽器以前沒賦予開發者的新功能。我將在每一單元列出這些從前不能實現的地方,以及他們所使用的其他 web 新技術。

標籤: 一個小複習

第一個標籤是老朋友了,它滿足的需求早於 Web Components。有時你只想存儲一些 HTML。也許有時你要多次複製標籤,也許有時你還不想馬上創建一個UI。 標籤包含並解析 HTML ,但不把解析出的DOM 添加到當前文檔中。

    

This won't display!

alert("this won't alert!"); 複製代碼

那麼解析出的 DOM 去哪了呢?它被添加到了「文檔碎片」中,可以把它理解成一個包含 html 的薄容器。當被添加到 DOM 中時文檔碎片就解體了,當你想保留一組稍後使用的標籤,又不想保留其容器時,文檔碎片非常有用。

「那麼,我該怎麼使用一個正在解體的容器中的標籤呢?」

答案是:你只需把模版的文檔碎片插入當前文檔即可:

let template = document.querySelector('template');
document.body.appendChild(template.content);
複製代碼

上面這段代碼可以正常執行,但是如果你剛解體了文檔碎片就會報錯!如果你重複運行上述代碼就會報錯。因為第二次運行時 template.content 已經沒有了。我們應該用一個碎片的拷貝代替 template.content ,然後再插入這個拷貝,代碼如下:

document.body.appendChild(template.content.cloneNode(true));
複製代碼

cloneNode 方法顧名思義,接收一個參數控制只拷貝標籤本身還是包括它的子標籤。

新知識點:

  • 標籤包含 HTML,但是不向當前文檔添加。

總結:

Custom Elements

Custom Elements是 Web Components標準的代表。它確實讓開發人員實現了自定義 HTML 標籤。這一切的實現得益於ES6 的 class 語法糖。如果你對 javascript 或者其他面向對象語言很熟悉的話,你可以像這樣通過繼承來實現自己的類:

class MyClass extends BaseClass {
    // class definition goes here
}
複製代碼

我們來試一下這樣寫:

class MyElement extends HTMLElement {}
複製代碼

不久之前這樣寫還會報錯。瀏覽器不允許原生 HTMLElement 類或其子類被繼承。Custom Elements 解除了這一限制。

瀏覽器會把

標籤映射到 HTMLParagraphElement 原生類,但是它怎麼映射自定義類呢?除了繼承內部類外,還有一個「自定義標籤註冊表」用於聲明這種映射:

customElements.define('my-element', MyElement);
複製代碼

現在頁面上的每個 標籤都與一個 MyElement 元素對應。 頁面每解析一個 標籤就調用一次 MyElement 的構造函數。

為什麼標籤名帶中橫線呢?標準制定者希望未來開發者可以自由的自定義標籤,這意味着開發者都可以創建 或者 這樣的標籤。為了避免未來的衝突,所有自定義標籤必須加中橫線,同時原生 HTML 標籤保證絕不包含中橫線。問題解決!

除了標籤創建時會調用構造函數,還有一系列生命周期函數會在特定時刻被調用:

  • connectedCallback 當元素被添加到文檔中時調用。這個函數可能多次調用,比如標籤移動、移除或重新添加時。
  • disconnectedCallbackconnectedCallback 相對應。
  • attributeChangeCallback 元素屬性更改時調用。

下面是一個稍複雜的例子:

class GreetingElement extends HTMLElement {
  constructor() {
    super();
    this._name = 'Stranger';
  }
  connectedCallback() {
    this.addEventListener('click', e => alert(`Hello, ${this._name}!`));
  }
  attributeChangedCallback(attrName, oldValue, newValue) {
    if (attrName === 'name') {
      if (newValue) {
        this._name = newValue;
      } else {
        this._name = 'Stranger';
      }
    }
  }
}
GreetingElement.observedAttributes = ['name'];
customElements.define('hey-there', GreetingElement);
複製代碼

在頁面上這樣使用:

Greeting
Personalized Greeting
複製代碼

如果要繼承一個 HTML 原生標籤,你可能會想定義一個看起來完全不同新標籤。比如讓 去繼承 複製代碼

這不是多此一舉,這樣程序就會知道 是繼承的

免责声明:本文内容来源于稀土掘金,已注明原文出处和链接,文章观点不代表立场,如若侵犯到您的权益,或涉不实谣言,敬请向我们提出检举。