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"/>
複製程式碼
那麼問題來了 偵錯程式上面只顯示了一個元素 它的拖拽把手(小圓點) 是哪來的呢?
接下來 開啟 控制面版 (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
哈哈