如何基于 WebComponents 封裝 UI 組件庫
如何基于?WebComponents?封裝?UI?組件庫
https://www.zoo.team/article/web-components

前言
作為一名前端攻城獅,相信大家也都在關(guān)注著前端的一些新技術(shù),近些年來前端組件化開發(fā)已為常態(tài),我們經(jīng)常把重用性高的模塊抽離成一個個的組件,來達(dá)到復(fù)用的目的,這樣減少了我們的維護(hù)成本,提高了開發(fā)的效率。但是都有一個缺點離不開框架本身,因為我們?yōu)g覽器本身解析不了那些組件。那么有沒有一種技術(shù)也可以達(dá)到這種效果呢?答案就是今天的主角 Web Components。
“Web Components 是一套不同的技術(shù),允許您創(chuàng)建可重用的定制元素(它們的功能封裝在您的代碼之外)并且在您的 web 應(yīng)用中使用它們。
目前 W3C 也在積極推動,并且瀏覽器的支持情況還不錯。FireFox、Chrome、Opera 已全部支持,Safari 也大部分支持,Edge 也換成 webkit 內(nèi)核了,離全面支持應(yīng)該也不遠(yuǎn)了。當(dāng)然社區(qū)也有兼容的解決方案 webcomponents/polyfills。
WebComponents 三要素和生命周期
Button 組件示例
首先我們就從一個最簡單的 Button 組件開始,我們可以通過在組件中傳入 type 來改變按鈕的樣式,并且動態(tài)監(jiān)聽了數(shù)據(jù)的變化。
//?html
<cai-button?type="primary">?
??<span?slot="btnText">
????按鈕
??span>
cai-button>
<template?id="caiBtn">
??<style>
????.cai-button?{
??????display:?inline-block;
??????padding:?4px?20px;
??????font-size:?14px;
??????line-height:?1.5715;
??????font-weight:?400;
??????border:?1px?solid?#1890ff;
??????border-radius:?2px;
??????background-color:?#1890ff;
??????color:?#fff;
??????box-shadow:?0?2px?#00000004;
????}
????.cai-button-warning?{
??????border:?1px?solid?#faad14;
??????background-color:?#faad14;
????}
????.cai-button-danger?{
??????border:?1px?solid?#ff4d4f;
??????background-color:?#ff4d4f;
????}
??style>
??<div?class="cai-button">?<slot?name="btnText">slot>?div>
template>
<script>
??const?template?=?document.getElementById("caiBtn");
??class?CaiButton?extends?HTMLElement?{
????constructor()?{
??????super()
??????this._type?=?{
????????primary:?'cai-button',
????????warning:?'cai-button-warning',
????????danger:?'cai-button-danger',
??????}
??????//?開啟?shadow?dom
??????const?shadow?=?this.attachShadow({
????????mode:?'open'
??????})
??????const?type?=?this
??????const?content?=?template.content.cloneNode(true)?//?克隆一份?防止重復(fù)使用?污染
??????//?把響應(yīng)式數(shù)據(jù)掛到?this
??????this._btn?=?content.querySelector('.cai-button')
??????this._btn.className?+=?`?${this._type[type]}`
??????shadow.appendChild(content)
????}
????static?get?observedAttributes()?{
??????return?['type']
????}
????attributeChangedCallback(name,?oldValue,?newValue)?{
??????this[name]?=?newValue;
??????this.render();
????}
????render()?{
??????this._btn.className?=?`cai-button?${this._type[this.type]}`
????}
??}
??//?掛載到?window
??window.customElements.define('cai-button',?CaiButton)
script>
三要素、生命周期和示例的解析
Custom elements(自定義元素): 一組 JavaScript API,允許您定義 custom elements 及其行為,然后可以在您的用戶界面中按照需要使用它們。在上面例子中就指的是我們的自定義組件,我們通過
class CaiButton extends HTMLElement {}定義我們的組件,通過window.customElements.define('cai-button', CaiButton)掛載我們的已定義組件。Shadow DOM(影子 DOM ):一組 JavaScript API,用于將封裝的“影子” DOM 樹附加到元素(與主文檔 DOM 分開呈現(xiàn))并控制其關(guān)聯(lián)的功能。通過這種方式,您可以保持元素的功能私有,這樣它們就可以被腳本化和樣式化,而不用擔(dān)心與文檔的其他部分發(fā)生沖突。使用
const shadow = this.attachShadow({mode : 'open'})在 WebComponents 中開啟。HTML templates(HTML 模板)slot :template 可以簡化生成 dom 元素的操作,我們不再需要 createElement 每一個節(jié)點。slot 則和 Vue 里面的 slot 類似,只是使用名稱不太一樣。
內(nèi)部生命周期函數(shù)
connectedCallback: 當(dāng) WebComponents 第一次被掛在到 dom 上是觸發(fā)的鉤子,并且只會觸發(fā)一次。類似 Vue 中的 mounted React 中的 useEffect(() => {}, []),componentDidMount。disconnectedCallback: 當(dāng)自定義元素與文檔 DOM 斷開連接時被調(diào)用。adoptedCallback: 當(dāng)自定義元素被移動到新文檔時被調(diào)用。attributeChangedCallback: 當(dāng)自定義元素的被監(jiān)聽屬性變化時被調(diào)用。上述例子中我們監(jiān)聽了 type 的變化,使 Button 組件呈現(xiàn)不同狀態(tài)。
雖然 WebComponents 有三個要素,但卻不是缺一不可的,WebComponents 借助 shadow dom ?來實現(xiàn)樣式隔離,借助 templates 來簡化標(biāo)簽的操作。
在這個例子用我們使用了 slot 傳入了倆個標(biāo)簽之間的內(nèi)容,如果我們想要不使用 slot 傳入標(biāo)簽之間的內(nèi)容怎么辦?
我們可以通過 innerHTML 拿到自定義組件之間的內(nèi)容,然后把這段內(nèi)容插入到對應(yīng)節(jié)點即可。
組件通信
了解上面這些基本的概念后,我們就可以開發(fā)一些簡單的組件了,但是如果我們想傳入一些復(fù)雜的數(shù)據(jù)類型(對象,數(shù)組等)怎么辦?我們只傳入字符串還可以么?答案是肯定的!
傳入復(fù)雜數(shù)據(jù)類型
使用我們上面的 Button,我們不僅要改變狀態(tài),而且要想要傳入一些配置,我們可以通過傳入一個 JSON 字符串
//?html
"btn">
</cai-button>
黄色视频图片免费看
|
五月天天天操
|
sv在线观看
|
翔田千里无码无删减hd
|
黄色视频网站在线免费看
|
