初識 Web Component

lijinke666發表於2018-12-21

1. 前言

元件化這個詞 應該大家耳朵都聽起繭巴了 在 Vue React Angular 三個大佬 的帶領下 , 我們前端 是否終於告別了 貼上複製的 "元件化" 時代

Antd ElementUi 這些高質量 且開箱即用 的 ui 庫更是讓元件化開發更上一層樓. 如果不編譯 或者 原生可以實現所謂的元件化嗎? w3c 給了我們 web component 的解決方案

2. 什麼是 Web Component

mdn 文件

作為開發者,我們都知道盡可能多的重用程式碼是一個好主意。這對於自定義標記結構來說通常不是那麼容易 — 想想複雜的HTML(以及相關的樣式和指令碼),有時您不得不寫程式碼來呈現自定義UI控制元件,並且如果您不小心的話,多次使用它們會使您的頁面變得一團糟。

Web Components旨在解決這些問題 — 它由四項主要技術組成,它們可以一起使用來建立封裝功能的定製元素,可以在你喜歡的任何地方重用,不必擔心程式碼衝突。

核心的四大要素

  • Custom elements(自定義元素):一組JavaScript API,允許您定義custom elements及其行為,然後可以在您的使用者介面中按照需要使用它們。

  • Shadow DOM(影子DOM):一組JavaScript API,用於將封裝的“影子”DOM樹附加到元素(與主文件DOM分開呈現)並控制其關聯的功能。通過這種方式,您可以保持元素的功能私有,這樣它們就可以被指令碼化和樣式化,而不用擔心與文件的其他部分發生衝突。

  • HTML templates(HTML模板)<template><slot> 元素使您可以編寫不在呈現頁面中顯示的標記模板。然後它們可以作為自定義元素結構的基礎被多次重用。

  • HTML Imports(HTML匯入):一旦定義了自定義元件,最簡單的重用它的方法就是使其定義細節儲存在一個單獨的檔案中,然後使用匯入機制將其匯入到想要實際使用它的頁面中。HTML 匯入就是這樣一種機制,儘管存在爭議 — Mozilla 根本不同意這種方法,並打算在將來實現更合適的。

3. Shadow DOM

瀏覽器為我們內建了很多元件 , 比如 最常用的

input,button,select, 這也是最屌的 相容三大框架的 ui 庫 :)

以 一個 範圍選擇條為例

<input type="range"/>
複製程式碼

初識 Web Component

那麼問題來了 偵錯程式上面只顯示了一個元素 它的拖拽把手(小圓點) 是哪來的呢?

接下來 開啟 控制面版 (Settings) => Elements => 勾選 (Show user agent shadow DOM)


初識 Web Component

可以清楚的看到 有一些額外的 div 元素 被隱藏掉了 小圓點 和 silder 這些樣式就是從這裡來的 這就是所謂的 shadow DOM,

Custom elements 自定義元素


在網頁中 我們可以寫 一些內建的標記 ,他們有自帶的一些樣式 padding ,margin 之類的

<div/>
<p/>
複製程式碼

也可以寫 自定義的 ,比如

<lijinke>666</lijinke>
複製程式碼

還是可以被正常解析 只不過沒有任何樣式

4. 開始寫一個簡單的 Web Component

認識了 上面兩點, 我們就可以 開始動手寫程式碼了,我們以一個卡片 (Card) 元件為例

4.1 首先我們定義 dom 結構

  <template id="my-card-template">
    <div class="my-card">
      <div class="title">
        <slot name="title">程式碼標題</slot>
      </div>
      <pre>
        <slot name="content">程式碼內容</slot>
      </pre>
    </div>
  </template>
複製程式碼

定義一個 template 模板 再定義兩個 slot 用於佔位 , 可以理解成 呼叫元件的時候 裡面的值會被替換,放心 這不是在寫 Vue

這時候 儲存 重新整理網頁, 大功告成

當然 這是不可能 接下來就是 利用 Vue-loader

new Vue({
    el:"#my-card-template"
})
複製程式碼

好吧, 這是不可能的 ,這時候頁面時一片空白

4.2 接下來 用 js 提供的介面 把 template 渲染出來

首先 寫一個類

  class MyCard extends HTMLElement {
    constructor(props) {
      super();
     }
  }
複製程式碼

第一步: 然後 拿到 template 裡面的內容 注意這裡 不是 innerHTML,

第二步: 將template 掛載在 shadow DOM 上面 (預設開啟)

如果 mode 設為 false 會沒有樣式

  class MyCard extends HTMLElement {
    constructor(props) {
      super();
      const {content:temp} = document.querySelector('#my-card-template')
      this.attachShadow({mode: 'open'}).appendChild(temp.cloneNode(true));
     }
  }
複製程式碼
4.3 註冊 自定義元件
customElements.define('my-card',MyCard)
複製程式碼

之後就可以在 html 裡面寫

  <my-card>
    <span slot="title">我是程式碼標題</span>
    <p slot="content">
      const a = 1;
      console.log(a)
    </p>
  </my-card>
複製程式碼

可以看到 template 裡面的 元素 變成了 shadow DOM 實現了 和 一樣的 shadow DOM 的效果 , 只是還沒有樣式


初識 Web Component
4.4 編寫元件樣式

接下來編寫樣式 寫一點簡單的 style

  <template id="my-card-template">
    <style>
      .my-card {
        width: 300px;
        height: 300px;
        background: #fff;
        box-shadow: 1px 2px 10px rgba(0, 0, 0, .3);
        margin: 10px
      }
      .title {
        height:40px;
        background: #dcdcdc;
        line-height: 40px;
        text-align: center;
      }
      pre {
        padding: 20px;
      }
    </style>
    <div class="my-card">
      <div class="title">
        <slot name="title">程式碼標題</slot>
      </div>
      <pre>
        <slot name="content">程式碼內容</slot>
      </pre>
    </div>
  </template>
複製程式碼

說真的 像 Vue 的三段式程式碼 哈哈.

4.5 預覽效果

初識 Web Component

5. 結語

Web Component 我也是出於好奇玩了玩 感覺 API 很不穩定 ,相容性很差

比如 匯入元件的 方法 隨時存在廢除的可能性

<link type="import" href="./xx.html">
複製程式碼

不過這確實是一個新的方向 和 新的可能性 作為前端 應該瞭解, 最近 w3c 推出來了很多新東西 , --自定義變數, css 版的 canvas api, 叫啥子我忘了, 自定義元件 , 原生模組載入, 前端的生態 是越來越好了, 所以

我還是用 React + Node.js 哈哈

本文 DEMO

參考資源