初識 Web Component

1. 前言

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

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

2. 什麼是 Web Component

mdn 文檔前端

做爲開發者,咱們都知道盡量多的重用代碼是一個好主意。這對於自定義標記結構來講一般不是那麼容易 — 想一想複雜的HTML(以及相關的樣式和腳本),有時您不得不寫代碼來呈現自定義UI控件,而且若是您不當心的話,屢次使用它們會使您的頁面變得一團糟。git

Web Components旨在解決這些問題 — 它由四項主要技術組成,它們能夠一塊兒使用來建立封裝功能的定製元素,能夠在你喜歡的任何地方重用,沒必要擔憂代碼衝突。github

核心的四大要素web

  • Custom elements(自定義元素):一組JavaScript API,容許您定義custom elements及其行爲,而後能夠在您的用戶界面中按照須要使用它們。canvas

  • Shadow DOM(影子DOM):一組JavaScript API,用於將封裝的「影子」DOM樹附加到元素(與主文檔DOM分開呈現)並控制其關聯的功能。經過這種方式,您能夠保持元素的功能私有,這樣它們就能夠被腳本化和樣式化,而不用擔憂與文檔的其餘部分發生衝突。api

  • HTML templates(HTML模板)<template><slot> 元素使您能夠編寫不在呈現頁面中顯示的標記模板。而後它們能夠做爲自定義元素結構的基礎被屢次重用。瀏覽器

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

3. Shadow DOM

瀏覽器爲咱們內置了不少組件 , 好比 最經常使用的

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

以 一個 範圍選擇條爲例

<input type="range"/>
複製代碼


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

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



能夠清楚的看到 有一些額外的 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 的效果 , 只是尚未樣式



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 預覽效果


5. 結語

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

好比 導入組件的 方法 隨時存在廢除的可能性

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

不過這確實是一個新的方向 和 新的可能性 做爲前端 應該瞭解, 最近 w3c 推出來了不少新東西 , --自定義變量, css 版的 canvas api, 叫啥子我忘了, 自定義組件 , 原生模塊加載, 前端的生態 是愈來愈好了, 因此

我仍是用 React + Node.js 哈哈

本文 DEMO

參考資源

相關文章
相關標籤/搜索