Web Components-LitElement 實(shí)踐
本文首發(fā)于政采云前端團(tuán)隊(duì)博客:Web Components-LitElement 實(shí)踐
https://www.zoo.team/article/webcomponents
前言
Google 在 2011 年首次正式提出 Web Components 組件化概念時(shí),它主要依賴三個(gè)技術(shù):Custom Element、Shadow Dom、HTML Templates。直到 2015 年 Google 才真正投入生產(chǎn)進(jìn)行使用,那時(shí)其他瀏覽器廠商還沒有大規(guī)模支持這個(gè)特性,應(yīng)用起來存在很大的兼容問題。
在這期間,Angular、React 和 Vue 三大框架崛起,并且都有“組件化”這個(gè)功能,也形成了各自的生態(tài)圈,但都與框架強(qiáng)關(guān)聯(lián)。由于這個(gè)原因,開發(fā)者對(duì)于 Web Components 的呼聲一直是只增不減。
直到今天,由于各大瀏覽器廠商的支持并結(jié)合 polyfills,在使用 Web Components 時(shí),兼容性已經(jīng)不是問題,開發(fā)者開始積極探索并實(shí)踐 Web Components 技術(shù)。
如何更好地應(yīng)用 Web Components 技術(shù)呢?有輕便的框架可以簡(jiǎn)化原生較為復(fù)雜的寫法嗎?那么我們來看看 LitElement 做了什么,能不能讓 Web Components 變得更好用些。
回顧
通過閱讀上篇文章《如何基于 Web Components 封裝 UI 組件庫(kù)》(https://juejin.cn/post/7096265630466670606),我們掌握了原生 Web Components 的一些內(nèi)容,包括:
三要素和生命周期;
基本的組件通信,包括如何利用 observedAttributes 屬性監(jiān)聽和 attributeChangedCallback 生命周期獲取最新屬性和通過 CustomEvent 拋出自定義事件來模擬實(shí)現(xiàn)狀態(tài)的“雙向綁定”;
如何設(shè)計(jì)組件庫(kù);
如何在原生、React 和 Vue 中優(yōu)雅地使用我們封裝的組件。
但使用 Web Components 的原生寫法確實(shí)存在一些不簡(jiǎn)潔的地方:
屬性監(jiān)聽:observedAttributes API 需要結(jié)合 attributeChangedCallback 生命周期,寫起來代碼量大;
組件通信時(shí)傳入復(fù)雜數(shù)據(jù)類型:只能通過 stringify 后的 attribute 傳遞,特殊對(duì)象格式如 Date,F(xiàn)unction 等傳遞起來會(huì)非常復(fù)雜,和現(xiàn)在的組件庫(kù)能力上相比功能會(huì)比較弱,使用場(chǎng)景相對(duì)單一;
組件通信時(shí)雙向綁定:需要結(jié)合自定義事件,寫法會(huì)比較復(fù)雜。
為了更豐富的開發(fā)場(chǎng)景和更好的開發(fā)體驗(yàn),LitElement 把以上問題進(jìn)行了歸納轉(zhuǎn)化,即:
如何響應(yīng) reactive properties的變化,并應(yīng)用到 UI 上。
如何解決模板語(yǔ)法。
它用了兩個(gè)核心庫(kù)來解決這個(gè)問題,分別是 lit-element 和 lit-html。
LitElement介紹
基本內(nèi)容
Lit 的核心是一個(gè)組件基類,它提供響應(yīng)式、scoped 樣式和一個(gè)小巧、快速且富有表現(xiàn)力的聲明性模板系統(tǒng),且支持 TypeScript 類型聲明。Lit 在開發(fā)過程中不需要編譯或構(gòu)建,幾乎可以在無工具的情況下使用。
我們知道 HTMLElement 是瀏覽器內(nèi)置的類,LitElement 基類則是 HTMLElement 的子類,因此 Lit 組件繼承了所有標(biāo)準(zhǔn) HTMLElement 屬性和方法。更具體來說,LitElement 繼承自 ReactiveElement,后者實(shí)現(xiàn)了響應(yīng)式屬性,而后者又繼承自 HTMLElement。
創(chuàng)建 Lit 組件還涉及許多概念,我們一一了解。
定義一個(gè)組件
Lit 組件作為 Custom Element 的實(shí)現(xiàn),并在瀏覽器中注冊(cè)。
原生的寫法主要是繼承 HTMLElement 類并重寫它的方法。而 LitElement 框架則是基于 HTMLElement 類二次封裝了 LitElement 類,它將很多的寫法通過一些語(yǔ)法糖的封裝變得更簡(jiǎn)單了,極大地簡(jiǎn)化了這些代碼。開發(fā)者只需繼承 LitElement 類開發(fā)自己的組件然后通過瀏覽器原生方法 customElements.define 注冊(cè)即可。
export class LitButton extends LitElement { /* ... */ }
customElements.define('lit-button', LitButton);
當(dāng)定義一個(gè) Lit 組件時(shí),就是定義了一個(gè)自定義 HTML 元素。因此,可以像使用任何內(nèi)置元素一樣使用新元素。
<lit-button type="primary"></lit-button>
渲染
組件具有 render 方法,該方法被調(diào)用以渲染組件的內(nèi)容。
雖然 Lit 模板看起來像字符串插值,但 Lit 解析并創(chuàng)建一次靜態(tài) HTML,然后只更新表達(dá)式中需要更改的值。
export class LitButton extends LitElement {
/* ... */
render() {
// 使用模板字符串,可以包含表達(dá)式
return html`
<div><slot name="btnText"></slot></div>
`;
}
}
通常,組件的 render() 方法返回單個(gè) TemplateResult 對(duì)象(與 html 標(biāo)記函數(shù)返回的類型相同)。
“TemplateResult對(duì)象:是 lit-html 接收模板字符串并經(jīng)過它的 html 標(biāo)記函數(shù)處理得到的一個(gè)純值對(duì)象。
但是,它可以返回 Lit 可以渲染的任何內(nèi)容,包括:
primitive 原始類型值,如字符串、數(shù)字或布爾值。
由 html 函數(shù)創(chuàng)建的 TemplateResult 對(duì)象。
DOM 節(jié)點(diǎn)。
任何受支持類型的數(shù)組或可迭代對(duì)象。
響應(yīng)式 properties
“DOM 中 property 與 attribute 的區(qū)別:
attribute 是 HTML 標(biāo)簽上的特性,可以理解為標(biāo)簽屬性,它的值只能夠是 String 類型,并且會(huì)自動(dòng)添加同名 DOM 屬性作為 property 的初始值;
property 是 DOM 中的屬性,是 JavaScript 里的對(duì)象,有同名 attribiute 標(biāo)簽屬性的 property 屬性值的改變也并不會(huì)同步引起 attribute 標(biāo)簽屬性值的改變;
Lit 組件接收標(biāo)簽屬性 attribute 并將其狀態(tài)存儲(chǔ)為 JavaScript 的 class 字段屬性或 properties。響應(yīng)式 properties 是可以在更改時(shí)觸發(fā)響應(yīng)式更新周期、重新渲染組件以及可選地讀取或重新寫入 attribute 的屬性。每一個(gè) properties 屬性都可以配置它的選項(xiàng)對(duì)象。
export class LitButton extends LitElement {
// 在靜態(tài)屬性類字段中聲明屬性,Lit 會(huì)處理為響應(yīng)式屬性
static properties = {
type: {
type: String,
reflect: true,
/*...其他選項(xiàng)屬性...*/
},
other: {
type: Object
}
};
/* ... */
}
它的選項(xiàng)對(duì)象可以具有以下屬性:
attribute:表示是否與 property 關(guān)聯(lián),或者 attribute 關(guān)聯(lián)屬性的自定義名稱。默認(rèn)值:true,表示 property 會(huì)與標(biāo)簽屬性 attribute 進(jìn)行關(guān)聯(lián)。如果設(shè)置為 false,則下面的 converter 轉(zhuǎn)換器、reflect 反射和 type 類型選項(xiàng)將被忽略。主要用來將 attribute 與 property 建立關(guān)聯(lián)。
type:在將 String 類型的 attribute 轉(zhuǎn)換為 property 時(shí),Lit 的默認(rèn)屬性轉(zhuǎn)換器會(huì)將 String 類型解析為給定的類型。將 property 反映到 attribute 時(shí)反之亦然。如果設(shè)置了 converter 轉(zhuǎn)換器,則將此字段傳遞給轉(zhuǎn)換器。如果未指定類型,則默認(rèn)轉(zhuǎn)換器將其視為 String 類型。
converter:用于在 attribute 和 property 之間轉(zhuǎn)換的自定義轉(zhuǎn)換器。如果未指定,則使用默認(rèn)屬性轉(zhuǎn)換器。主要用來決定 attribute 與 property 確定建立關(guān)聯(lián)后如何進(jìn)行數(shù)據(jù)轉(zhuǎn)換,畢竟 attribute 只能是 String 類型而 property 卻是可以自定義的類型,默認(rèn)屬性轉(zhuǎn)換器則是依據(jù) property 配置的 type 選項(xiàng)進(jìn)行目標(biāo)類型的轉(zhuǎn)換。上例中表示接受的 other 屬性的 attribute 后會(huì)序列化為目標(biāo) Object 類型。
hasChanged:每當(dāng)設(shè)置屬性時(shí)調(diào)用的函數(shù)以確定屬性是否已更改,并應(yīng)觸發(fā)更新。如果未指定,LitElement 將使用嚴(yán)格的不等式檢查 (newValue !== oldValue) 來確定屬性值是否已更改。
reflect:property 屬性值是否反映回關(guān)聯(lián)的 attribute 屬性。默認(rèn)值:false,即 property 的改變不會(huì)主動(dòng)引起 attribute 的改變。上例中表示接收 type 組件屬性 properties 的改動(dòng)會(huì)同步到對(duì)應(yīng) attribute 標(biāo)簽屬性上。
state:設(shè)置為 true 以將 property 屬性聲明為內(nèi)部 state。內(nèi)部 state 的改變也會(huì)觸發(fā)更新,就像響應(yīng)式屬性 property,但 Lit 不會(huì)為其生成 attribute 屬性,用戶不應(yīng)從組件外部訪問它。這些屬性應(yīng)標(biāo)記為 private 或 protected。還建議使用前導(dǎo)下劃線 (_) 之類的約定來標(biāo)識(shí) JavaScript 用戶的 private 或 protected 屬性??梢詾?state 內(nèi)部狀態(tài)指定的唯一選項(xiàng)是 hasChanged 函數(shù)。
省略選項(xiàng)對(duì)象或指定一個(gè)空的選項(xiàng)對(duì)象等效于為所有選項(xiàng)指定默認(rèn)值。
另外,Lit 為每個(gè)響應(yīng)式屬性生成一個(gè) getter/setter 對(duì)。當(dāng)響應(yīng)式屬性發(fā)生變化時(shí),組件會(huì)安排更新。Lit 也會(huì)自動(dòng)應(yīng)用 super 類聲明的屬性選項(xiàng)。除非需要更改選項(xiàng),否則不需要重新聲明該屬性。
樣式
組件模板被渲染到它的 shadow root。添加到組件的樣式會(huì)自動(dòng)作用于 shadow root,并且只會(huì)影響組件 shadow root 中的元素。
Shadow DOM 為樣式提供了強(qiáng)大的封裝。如果 Lit 沒有使用 Shadow DOM,則必須非常小心不要意外地為組件之外的元素設(shè)置樣式,無論是組件的父組件還是子組件。這可能涉及編寫冗長(zhǎng)而繁瑣的類名。通過使用 Shadow DOM,Lit 確保編寫的任何選擇器僅適用于 Lit 組件的 shadow root 中的元素。
可以使用標(biāo)記的模板 css 函數(shù)在靜態(tài) styles 類字段中定義 scoped 樣式。
export class LitButton extends LitElement {
// 使用純 CSS 為組件定義 scoped 樣式
static styles = css`
.lit-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;
cursor: pointer;
}
`;
/* ... */
}
如圖同樣應(yīng)用了 lit-button 樣式,但樣式只對(duì) shodow root 中的部分起作用。
靜態(tài) styles 類字段的值可以是:
單個(gè)標(biāo)記的模板文字。
static styles = css`...`;
一組標(biāo)記的模板文字。
static styles = [ css`...`, css`...`];
此外,styles 也支持在樣式中使用表達(dá)式、使用語(yǔ)句、繼承父類樣式、共享樣式、使用 unicode escapes 以及在模板 template 中使用樣式等功能。Lit 也提供了兩個(gè)指令,classMap 和 styleMap,可以方便地在 HTML 模板中條件式的應(yīng)用 class 和 style。
import {LitElement, html, css} from 'lit';
import {classMap} from 'lit/directives/class-map.js';
import {styleMap} from 'lit/directives/style-map.js';
export class LitButton extends LitElement {
static properties = {
classes: {},
styles: {},
};
static styles = css`
.lit-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;
cursor: pointer;
}
.someclass {
color: #000;
}
.anotherclass {
font-size: 16px;
}
`;
constructor() {
super();
this.classes = {'lit-button': true, someclass: true, anotherclass: true};
this.styles = {fontFamily: 'Roboto'};
}
render() {
return html`
<div class=${classMap(this.classes)} style=${styleMap(this.styles)}>
<slot name="btnText"></slot>
</div>
`;
}
}
customElements.define('lit-button', LitButton);
生命周期
Lit 組件可以繼承原生的自定義元素生命周期方法。但如果需要使用自定義元素生命周期方法,確保調(diào)用 super 類的生命周期,以保證父子組件生命周期的一致。
標(biāo)準(zhǔn)的自定義組件生命周期
constructor():創(chuàng)建元素時(shí)調(diào)用。適用于執(zhí)行必須在第一次更新之前完成的一次性初始化任務(wù)。
connectedCallback():在將組件添加到文檔的 DOM 時(shí)調(diào)用。適用于僅在元素連接到文檔時(shí)才發(fā)生的任務(wù)。其中最常見的是將事件偵聽器添加到元素節(jié)點(diǎn)。
disconnectedCallback():當(dāng)組件從文檔的 DOM 中移除時(shí)調(diào)用,用于移除對(duì)元素的引用。比如移除添加到元素節(jié)點(diǎn)的事件偵聽器。
attributeChangedCallback():當(dāng)元素的 observedAttributes 之一更改時(shí)調(diào)用。
adoptedCallback():當(dāng)組件移動(dòng)到新文檔時(shí)調(diào)用。
connectedCallback() {
super.connectedCallback()
addEventListener('keydown', this._handleKeydown);
}
disconnectedCallback() {
super.disconnectedCallback()
window.removeEventListener('keydown', this._handleKeydown);
}
除了標(biāo)準(zhǔn)的自定義元素生命周期之外,Lit 組件還實(shí)現(xiàn)了響應(yīng)式更新周期。Lit 異步執(zhí)行更新,因此屬性更改是批處理的,如果在請(qǐng)求更新后但在更新開始之前發(fā)生了更多屬性更改,則所有更改都將在同一個(gè)更新中進(jìn)行。當(dāng)響應(yīng)式 prpperties 屬性發(fā)生變化或顯式調(diào)用 requestUpdate() 方法時(shí),將觸發(fā)響應(yīng)更新周期,它會(huì)將更改呈現(xiàn)給 DOM。
響應(yīng)式更新周期
第一階段:觸發(fā)更新
haschanged():在設(shè)置響應(yīng)式屬性時(shí)隱式調(diào)用。默認(rèn)情況下 hasChanged() 會(huì)進(jìn)行嚴(yán)格的相等性檢查,如果返回 true,則會(huì)安排更新。
requestUpdate():調(diào)用 requestUpdate() 來安排顯式更新。如果需要在與屬性無關(guān)的內(nèi)容發(fā)生更改時(shí)更新和呈現(xiàn)元素,將很有用。
connectedCallback() {
super.connectedCallback();
this._timerInterval = setInterval(() => this.requestUpdate(), 1000);
}
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this._timerInterval);
}
第二階段:執(zhí)行更新
shouldUpdate():調(diào)用以確定是否需要更新周期。
willUpdate():在 update() 之前調(diào)用以計(jì)算更新期間所需的值。
update():調(diào)用以更新組件的 DOM。
render():由 update() 調(diào)用,并應(yīng)實(shí)現(xiàn)返回用于渲染組件 DOM 的可渲染結(jié)果(例如 TemplateResult)。
第三階段:完成更新
firstUpdated():在組件的 DOM 第一次更新后調(diào)用,緊接在調(diào)用 updated() 之前。
updated():每當(dāng)組件的更新完成并且元素的 DOM 已更新和呈現(xiàn)時(shí)調(diào)用。
updateComplete():updateComplete Promise 在元素完成更新時(shí)更新為 resolved 狀態(tài)。
其他:
performUpdate():調(diào)用 performUpdate() 以立即處理掛起的更新。這通常不需要,但在需要同步更新的極少數(shù)情況下可以這樣做。
hasUpdated():如果組件至少更新過一次,則 hasUpdated 屬性返回 true。僅當(dāng)組件尚未更新時(shí),才可以在任何生命周期方法中使用 hasUpdated 來執(zhí)行工作。
getUpdateComplete():在執(zhí)行 updateComplete 之前等待其他條件執(zhí)行完成。
整個(gè)流程圖示如下:
了解了基本的概念和內(nèi)容,如果你做過任何現(xiàn)代的、基于組件的 Web 開發(fā),你應(yīng)該對(duì) Lit 的系列概念和用法感到似曾相識(shí)并且容易上手。下面通過一些案例了解 LitElement 的其他特性。
傳入復(fù)雜數(shù)據(jù)類型
對(duì)于復(fù)雜數(shù)據(jù)的處理,為什么會(huì)存在這個(gè)問題,根本原因還是因?yàn)?attribute 標(biāo)簽屬性值只能是 String 類型,其他類型需要進(jìn)行序列化。在 LitElement 中,只需要在父組件模板的屬性值前使用(.)操作符,這樣子組件內(nèi)部 properties 就可以正確序列化為目標(biāo)類型。
/**
* 父組件-復(fù)雜數(shù)據(jù)類型
*/
import { html, LitElement } from 'lit';
import './person';
class LitComplex extends LitElement {
constructor() {
super();
this.person= {'name':'cai'};
this.friends = [{'name':'zheng'},{'name':'yun'}];
}
render() {
return html`
<div>復(fù)雜數(shù)據(jù)類型</div>
<lit-person .person=${this.person} .friends=${this.friends}></lit-person>
`
}
}
customElements.define('lit-complex', LitComplex);
export default LitComplex;
/**
* 基礎(chǔ)組件
*/
import { html, LitElement } from 'lit';
class LitPerson extends LitElement {
static properties = {
person: {
type: Object
},
friends: {
type: Array,
},
date: {
type: Date,
}
}
firstUpdated() {
console.log(this.person instanceof Object, this.friends instanceof Array, this.date instanceof Date);
// true true true
}
render() {
return html`
<div>${this.person.name}有${this.friends.length}個(gè)朋友</div>
`
}
}
customElements.define('lit-person', LitPerson);
export default LitPerson;
這樣可以支持各種類型數(shù)據(jù)的傳遞使用。
數(shù)據(jù)的雙向綁定
/**
* 數(shù)據(jù)綁定- father
*/
import { html, LitElement } from 'lit';
import './lit-input';
class LitInputFather extends LitElement {
static properties = {
data: {
type: String
}
}
constructor() {
super();
this.data = 'default';
}
render() {
return html`
<lit-input value=${this.data}></lit-input>
`;
}
}
customElements.define('lit-input-father', LitInputFather);
export default LitInputFather;
/**
* 數(shù)據(jù)綁定
*/
import { html, LitElement } from 'lit';
class LitInput extends LitElement {
static properties = {
value: {
type: String,
reflect: true
}
}
change = (e) => {
this.value = e.target.value;
}
render() {
return html`
<div>輸入:<input value=${this.value} @input=${this.change}/></div>
`
}
}
customElements.define('lit-input', LitInput);
export default LitInput;
這里子組件接收了父組件的 value 屬性,默認(rèn)值設(shè)為了 'default',在子組件內(nèi)通過監(jiān)聽輸入事件更新了 value 值,因?yàn)?value 屬性配置了 reflect 為 true,即可將屬性值的改變反映回關(guān)聯(lián)的 attribute 屬性。
如圖:input 組件默認(rèn)值為 'default'并在緊接著輸入'123'后,組件的標(biāo)簽屬性 value 同時(shí)發(fā)生了變化。
這時(shí)在父組件通過獲取子組件的 attribute 即可獲得子組件同步改動(dòng)的值。以此實(shí)現(xiàn)數(shù)據(jù)的雙向綁定,但 LitElement 本身是單向的數(shù)據(jù)流。
指令使用
指令是可以通過自定義表達(dá)式呈現(xiàn)方式來擴(kuò)展 Lit 的函數(shù)。Lit 包含許多內(nèi)置指令,可幫助滿足各種渲染需求:以組件緩存為例。
在更改模板而不是丟棄 DOM 時(shí)緩存渲染的 DOM。在大型模板之間頻繁切換時(shí),可以使用此指令優(yōu)化渲染性能。
/**
* cache 內(nèi)置指令使用
*/
import {LitElement, html} from 'lit';
import {cache} from 'lit/directives/cache.js';
class LitCache extends LitElement {
static properties = {
show: false,
data: {},
};
constructor() {
super();
this.data = {
detail: 'detail',
sumary: 'sumary'
};
}
detailView = (data) => html`<div>${data.detail}</div>`;
summaryView = (data) => html`<div>${data.sumary}</div>`
changeTab = () => {
this.show = !this.show;
}
render() {
return html`${cache(this.show
? this.detailView(this.data)
: this.summaryView(this.data)
)}
<button @click=${this.changeTab}>切換</button>
`;
}
}
customElements.define('lit-cache', LitCache);
這個(gè)例子在模板中使用了語(yǔ)句表達(dá)式,再通過 click 事件切換組件時(shí)展示不同的模板內(nèi)容;引入了 cache 指令函數(shù),實(shí)現(xiàn)了 DOM 的緩存。
LitElement 內(nèi)置了大量的指令函數(shù)可以使用。
此外,它還有豐富的 Mixins 和 Decoratrs 等內(nèi)容值得細(xì)細(xì)學(xué)習(xí),在此不再做過多展開。
總結(jié)
總的來說,LitElement 在 Web Components 開發(fā)方面有著很多比原生的優(yōu)勢(shì),它具有以下特點(diǎn):
簡(jiǎn)單:在 Web Components 標(biāo)準(zhǔn)之上構(gòu)建,Lit 添加了響應(yīng)式、聲明性模板和一些周到的功能,減少了模板文件。
快速:更新速度很快,因?yàn)?Lit 會(huì)跟蹤 UI 的動(dòng)態(tài)部分,并且只在底層狀態(tài)發(fā)生變化時(shí)更新那些部分——無需重建整個(gè)虛擬樹并將其與 DOM 的當(dāng)前狀態(tài)進(jìn)行比較。
輕便:Lit 的壓縮后大小約為 5 KB,有助于保持較小的包大小并縮短加載時(shí)間。
高擴(kuò)展性:lit-html 基于標(biāo)記的 template,它結(jié)合了 ES6 中的模板字符串語(yǔ)法,使得它無需預(yù)編譯、預(yù)處理,就能獲得瀏覽器原生支持,并且擴(kuò)展能力強(qiáng)。
兼容良好:對(duì)瀏覽器兼容性非常好,對(duì)主流瀏覽器都能有非常好的支持。
結(jié)合這些點(diǎn),基本可以滿足項(xiàng)目開發(fā)中的大部分場(chǎng)景。
以上就是關(guān)于 LitElement 介紹的主要內(nèi)容,更多內(nèi)容可以前往官網(wǎng)學(xué)習(xí)了解,文中案例地址可以在此獲得 (https://github.com/CYLpursuit/lit-element-ui),同時(shí)推薦安裝 lit-plugin (https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin) VS Code 插件來更好的預(yù)覽和改動(dòng)代碼。
尾聲
我們知道,W3C 仿照 jQuery 的 $ 函數(shù),實(shí)現(xiàn)了 querySelector() 和 querySelectorAll() 方法并逐漸取代了 jQuery 快速選擇 DOM 元素的功能,加速了 jQuery 的沒落,帶著前端邁向了新的階段。那么隨著 Web Components 的不斷發(fā)展,它會(huì)取代現(xiàn)有的前端框架嗎?
現(xiàn)階段來看,還并不會(huì),因?yàn)?Web Components 與各前端框架之間的關(guān)系是“共存”而非互斥,兩者可以完美地互補(bǔ)。雖然前端框架 React 和 Vue 中組件化是其中非常重要的功能,但它們還有頁(yè)面路由,數(shù)據(jù)綁定,模塊化,CSS 預(yù)處理器,虛擬 DOM,Diff 算法以及各種龐大的生態(tài)等功能。而 Web components 所解決的僅僅是組件化這么一項(xiàng)功能。不論是 React 還是 Vue,從它們的官方文檔有關(guān)于 Web Components 的說明中,都可以更好幫助我們理解它們與 Web Components 之間的關(guān)系。
UI組件庫(kù)
shoelace (https://shoelace.style/)
Wired Elements (https://wiredjs.com/)
UI5 Web Components (https://sap.github.io/ui5-webcomponents/playground/getting-started)
Kor (https://kor-ui.com/introduction/welcome)
參考資料
WebComponents | MDN (https://developer.mozilla.org/en-US/docs/Web/Web_Components)
webcomponents/polyfills | Github (https://github.com/webcomponents/polyfills)
LitElement | 官方文檔 (https://lit.dev/docs/components/overview/)
作者:鹿竹
歡迎關(guān)注微信公眾號(hào) :政采云前端團(tuán)隊(duì)