看了Quark Design后,我去深入了解了Web Components
?1.寫在前面
最近哈啰單車前端團隊開源的Quark Design組件庫,號稱是下一代前端組件庫,可以同時在任意框架或無框架中使用。
那么,什么是Web Components?
2.什么是Web Components?
現今前端生態中框架層出不窮,在生產中為了提升效率和標準化組件,就會針對框架開發組件庫。但是各種框架之間是不兼容的,對此需要對應開發適應框架的組件庫,這樣也造成維護成本攀升。就如同物理界有電磁相互作用、強相互作用以及弱相互作用,需要單獨的物理理論來解釋這三種作用造成的物理現象,這樣讓眾多物理學家在朝著大統一理論前進,而Web Components可以看作是現今UI組件庫"大統一理論"的一種解決方案。
Web Components與React、Vue?等框架中的組件類似,其實在Vue中也采用了很多基于Web Components?的設計。這是一個可復用的UI構建模塊,封裝了所有渲染所需要的HTML、CSS?以及基于Javascript?的邏輯。最大的區別是,它不依賴于特定的JavaScript框架,而是利用瀏覽器原生提供的技術,這樣你的Web組件就與框架無關了。
3.Web Components的主要內容
Web Components的主要內容如下:
- Custom Elements?:原生提供的API,用于可自定義Custom Elements和行為。
- Shadow DOM:原生提供的API,用于封裝與主文檔DOM隔離的私有DOM,不受外部DOM的樣式和行為的影響。
- Templates:
- Attributes:
- Slots:
- Life cycle methods:
接下來,跟隨我的腳步在例子中逐個實現這些概念,逐個擊破理論。
4.Custom Elements
Custom Elements是Web Components?中的一個重要特性,可以提供給開發者將html的功能封裝為自定義標簽,方便進行復用。也就是說,Custom Elements?本質上是用戶用于實現在html?中有效使用的,類似<div>、<button>?等自定義標簽。最大區別在于,自定義標簽有著自己的模板、行為和標簽名稱,通過Javascript的API實現的。
Custom Elements?總是使用連字符-?進行自定義標簽的標識,即<one-button/>?,各大瀏覽器公司達成公司不在創建任何新的標簽元素,來防止元素沖突。熟悉vue框架的開發者應該知道,在vue中的自定義組件命令有<OneButton/>或<one-button/>?這種結構,官方推薦的是<one-button/>這種使用方式。
通過customElements.define來簡單注冊自定義組件,下面就來簡單實踐下:
運行展示:
5.Shadow DOM
Shadow DOM?與原生DOM的區別就是用戶自定義封裝的DOM,本質上還是DOM元素。不同的是,Shadow DOM?可以將自定義的DOM片段與其他DOM進行隔離,可以實現樣式不受外部DOM的影響,類似于使用iframe?內嵌了一個html。也正是Shadow DOM的存在,能夠進行DOM隔離、實現獨立的組件王國,使得自定義組件跨域框架的約束,不再耦合,確保在任何無框架和任何框架中正常使用。
如圖所示:
圖示來自MDN文檔
一些 Shadow DOM 特有的術語:
- Shadow host:一個常規 DOM 節點,Shadow DOM 會被附加到這個節點上。
- Shadow tree:Shadow DOM 內部的 DOM 樹。
- Shadow boundary:Shadow DOM 結束的地方,也是常規 DOM 開始的地方。
- Shadow root: Shadow tree 的根節點。
Shadow DOM ?并不是新生事物,在原生<video>?標簽中其實就有內置的Shadow DOM ?,包含一系列的按鈕和其他控制器等。而Web Components?只不過是允許用戶根據需要使用Shadow DOM來實現自定義標簽。
那么,就接著上面的例子一起來實現下:
運行得到:
在上面運行結果中,實現的展示效果是一樣,但是渲染的dom節點卻有所不同,在使用shadow dom?實現的標簽中會有#shadow-root字樣標識。
接下來,我們給他們添加上樣式,進行對比:
運行結果:
在上面代碼片段中,在全局對button?標簽進行設置樣式,運行結果表明并未影響到shadow dom中的樣式。
6.Template
見到template?模板,使用過vue框架的開發者就再熟悉不過了,template?標簽本身不會在html?中進行立即渲染,而是用于對待使用的代碼進行標記,在需要被使用的時候才會進行渲染。也正是因為template?的特性,使得我們可以將一些可重復使用的代碼用template?進行組織,通過javascript獲取它的引用,再添加到DOM中。
For Example:
在上面代碼片段中,可以看到在需要使用的時候將模板內容追加到shadow dom中,即模板內容不會立即被渲染,而是在被調用后才會在頁面進行渲染。
注意:
為什么這里使用Node.cloneNode() 方法添加了模板的拷貝到陰影的根結點上?
這是因為在添加模板內容到shadow dom?時,后續可以添加樣式信息到模板的style標簽上,也會將其封裝到自定義標簽中,倘若直接將模板添加到原生DOM元素中不起作用的。
7.Slots
插槽由其name屬性標識,并且允許您在模板中定義占位符,當在標記中使用該元素時,該占位符可以填充所需的任何 HTML 標記片段。使用過vue框架的開發者,對這部分內容再熟悉不過了。
運行結果:
在上面片段中,在使用自定義標簽的時候,如果<one-button>?中沒有插入任何內容,展示的將是hello onechuan?,倘若在在使用時插入了自定義內容,則展示自定義內容hello yichuan。
當然,當自定義組件中有多個地方使用插槽,可以通過給每個插槽命名進行標識,即:命名插槽。
類似于:vue中的mount。
運行結果:
?connectedCallback
connectedCallback?方法會在自定義組件插入DOM的首次渲染時調用一次。此時 shadow dom?已經掛載到DOM樹上,對此可以通過connectedCallback?方法來訪問shadow dom上的屬性、子元素以及監聽事件。倘若組件被移除或被移動,將會再次被調用。
運行結果:
在上面代碼片段中,看到在進行渲染初始化后,會進行執行一次connectedCallback的內容。
?attributeChangedCallback
監聽custom element?自身屬性的增刪改,當發生狀態改變時調用此方法,在使用前必須在一個observedAttributes() ?的靜態方法中定義要觀察的屬性。該方法返回一個屬性名稱的數組。一旦observedAttributes?返回了屬性值數組,則attributeChangedCallback方法會在每次該屬性變化時調用。
這個方法有三個參數:屬性名稱被改變,該屬性的舊值,以及更新的值。當this.setAttribute()觸發時,屬性會被更新。
disconnectedCallback
當 custom element? 從文檔 DOM? 中刪除時,disconnectedCallback被調用。
8.寫在最后
在我們上述實現的自定義組件,可以在整個項目中重復使用。簡而言之,在構建Web Components時,步驟如下:
- 首先,必須使用customElements.define()注冊自定義元素;
- 構造函數會調用,將節點添加到shadow dom中
- 然后,進行一次初始化,執行connectedCallback方法;
- 當元素的屬性被更新時,它的attributeChangedCallback()被觸發;
- 當一個事件從元素中被移除時,disconnectedCallback()方法被調用以清理事件監聽器。
- shadow dom - 是DOM的一個封裝版本,用于防止CSS泄露。
- Slots ?- 用于添加和訪問自定義元素組件的子元素,也有一種特殊的方式來訪問使用命名為Slot的子元素。
本文參考和整理了許多文檔資料,學而知不足,繼續前行。
9.參考文章
《Web Components Basic to Advanced》
《MDN文檔》
《重磅!哈啰 Quark Design 正式開源,下一代跨技術棧前端組件庫》