談談WebComponents | 前端開發

eeaa637bb0b3ae55dbd787ebd793ccdc.png

一、?源起

讓我們以一個例子開始。

假設我們要做一個環形進度條,它可以:

1、根據進度數值的不同,計算出百分比,以渲染對應的角度值。

2、根據設置的進度不同,我們用不同的顏色加以區分。

3、在環的中間我們以動畫遞增的方式顯示進度。

最終的效果,大致如下圖:

c54e9bc45ef1e17812de3890a4cb4860.gif

除了直接用組件庫,聰明的你肯定已經想到了多種解決辦法。如使用現代前端框架React/Vue/Angular/SvelteJS/SolidJS等等,你可能會找到或編寫對應的組件,通過相應數據狀態的變更,完成相對復雜的交互;又如在小快靈的項目下,用jQuery的Widget開發也是一個不錯的選擇;再或者,你可以點開你的HTML+JavaScript+CSS技能樹,純手工打造一個。這都是可以完成的任務。

這里[1]就是一個針對這個需求的實現。

當然,在完成之后,你可能會考慮對組件做一些提煉,下次再遇到同樣的需求,你就可以氣定神閑地“開箱即用”。通常,我們希望撰寫的代碼能夠實現在UI以及行為層面的復用。所以,以組件為單位進行代碼復用的需求也就呼之欲出。

實際上,除了Web前端外,各種相關的界面技術,比如安卓和蘋果App、Windows軟件、Qt以及Flutter等等,都發展出了類似的組件化技術。可以說,組件化是界面技術發展到一定復雜程度的必然產物。

為了放心地復用組件,除了代碼層面的復用方案,也要包含一定的隔離特性:我們希望元素的樣式、行為能夠不被其他的代碼干擾,也不會干擾到頁面其他的元素,即存在一定的隔離性。考慮下面的代碼:

5843f8983036b784ded9166b827430aa.png

考慮上述第10行到20行,以及21行到29行分別來自不同的組件。這里第二個組件的加入就會影響第一個組件的行為。第一個組件也在完全不知情的情況下被莫名其妙地變更了行為、樣式。

當然,這樣的代碼是精心簡化過的,實際上的工程代碼不會這樣撰寫。但復雜的代碼會造成問題被隱藏的更深,更加難以發現。我們當然可以直接詰問開發者的慮事不周,不過更理智的做法是提煉一些工程化的方法來避免這種問題的發生。比如Vue框架中的scoped樣式。歸根到底的問題在于,早期的HTML、CSS缺乏封裝所必須的特性。

為了彌補這一缺陷,技術人員做了各種探索。

“上古時期”,微軟在IE系列曾實現過一種名曰“HTC”的技術,我們甚至還能從互聯網上找到這個技術的蛛絲馬跡[2]。它實現了組件模版、樣式、行為的復用和隔離方案。然而這項技術是IE Only的技術,后面隨著大廠博弈以及各種標準化方案的誕生,這個方案在IE10以后便逐漸退出歷史舞臺。

Firefox在2007年左右也曾經支持過一個封裝方案,叫XML Binding Language[3]。不過這項技術也由于主要在Firefox支持,也已經逐步淡出。

前端的框架如Angular、React、Vue等等,都提供了組件的復用和行為隔離的方案。不過由于瀏覽器層面對于前端框架的語法不支持,一般會需要在部署在生產環境前作一定的前端編譯,這也是目前前端開發的標準做法。

針對這些需求,W3C標準化項目組,在2011年前后提出了WebComponents標準,現在由WhatWG進行維護。Web Components最終試圖HTML、CSS和DOM API層面配合瀏覽器試圖解決這些問題,是一種新的瀏覽器特性,同時也是一個復合的標準,提供了Web開發中組件的實現模型。

Web Components也是這篇文章的主角。

二、?標準細節

目前認為,Web Components是一組標準的集合。針對集合涵蓋的內容,各個版本有不同的定義。由于篇幅所限,本文我們主要針對三個核心展開講解,分別是Custom Elements、HTML template以及Shadow Dom。最新版本的瀏覽器還支持ES Modules,恰當的使用ES Modules,有利于模塊的復用,在這種情況下,我們也可以把這個標準囊括進標準集合中。

2-1 Custom Elements

Custom Elements的出現,主要是為了解決HTML標簽的有限性。它允許開發者自定義標簽,并為其添加默認的行為、樣式。

那么,如何來定義呢?下面是標準語法:

165f20b84c6d8954546880c56fd8ef73.png

這里是否傳遞第三個參數,決定了定義元素的類型。

如果增加了第三參數,則直接繼承該HTML元素的行為,稱為Customized built-in elements(自定義內置元素)。比如繼承了HTMLImageElement,則繼承了img標簽元素的所有默認行為和樣式。

如果缺省,該元素直接繼承HTMLElement,稱為Autonomous custom elements(自主自定義元素)。比如我們定義了一個user-card的標簽,之后,我們就能直接使用<user-card></user-card>來引入這種標簽的默認樣式和行為。

我們首先來看一個自定義內置元素的例子:

28d79fb90c733b4aa16c9814fe3e3514.png

上述代碼擴展了html默認的button元素,定義了一個hello-button組件。

這段代碼有兩個關鍵點:

1.CustomElements.define 需要指定第三個擴展參數。

2.使用時,使用is屬性,來指定隸屬的自定義元素名。

默認的,每個hello-button都會有button的所有屬性,但增加了一點:點擊會默認彈出“Hello!”。組件的示例依然可以定義事件,并且不會覆蓋定義類上定義的事件。

需要說明的是,目前(2024年6月)safari瀏覽器最新版依然沒有對自定義內置元素進行支持,Chrome、Edge、Firefox、Opera等都提供了支持。

接下來,我們再來看一下自主自定義元素。這個特性目前瀏覽器支持較好,主流的瀏覽器都已提供支持。

a378b4e78e8ebdb840efc7e39ca23410.png

之后我們在html里面加入:

7226a3a032a7d55461bf7cab745fae07.png

就可以顯示了。這似乎有點像我們熟悉的React/Vue組件的用法了。

CustomElements支持生命周期的回調。

生命周期

說明

connectedCallback()

每當元素添加到文檔中時調用。

disconnectedCallback()

每當元素從文檔中移除時調用。

adoptedCallback()

每當元素被移動到新文檔中時調用。

attributeChangedCallback()

在屬性更改、添加、移除或替換時調用。

需配合靜態的observedAttributes屬性。

這里是一個在線的例子[4],讀者可以嘗試一下。

2-2 HTML template

上一節我們寫的user-card組件,里面都是用dom方法動態創建的。這樣不但麻煩,而且運行效率也偏低。為此,WebComponents標準提供了HTML templates的方式。

622295ec6cc527ab42042d72def8c3c5.png

<template>標簽也可以多次復用。

盡管到這一步已經挺好了,但是元素仍舊不是很靈活。我們只能在里面顯示一點文本,這里,可以使用 <slot> 插槽元素通過聲明式的語法在每個元素實例中顯示不同的文本。插槽由其 name 屬性標識,并且允許開發者在模板中定義占位符,當在標記中使用該元素時,該占位符可以填充所需的任何 HTML 標記片段。

我們在上述代碼的第18行增加下列代碼:

b1c5aa4c6f70347b2b7551761fe6da7e.png

同時我們在調用時使用:

28e846924bab56918382aaa2ab4fc2f9.png

則完成了文字動態傳入。

9667282ac6e22602ecf7ea136a3c0244.png

再進一步,我們索性支持外界傳值支持一下。

76e93914a48f78795ae40f71697ea322.png

這樣在調用時候,我們就可以用外界傳遞的圖片了:

a6e4dfa9440132ec328c3a656a94d303.png

我們還可以在template標簽里用<style>標簽增加必要的樣式。至此,我們基本上完成了這個自定義組件。這里是完整的代碼[5]

之所以寫在組件里,也就間接實現了封裝。這樣定義出的樣式,理論上不會影響其他的元素。

這里:

4fb5843deb3802bd76c4e58d2250f276.png

偽類,選擇包含使用這段 CSS 的 Shadow DOM 的影子宿主。具體到這個例子,我們的指的是這里:

8b2555d6ee8a0d28332b6dca1bd15987.png

為了最終實現封裝,我們再來引出第三項技術:Shadow Dom。

2-3 Shadow Dom

自定義元素從定義上來說是一種可重用功能:它可以被放置在任何網頁中,并且期望它能夠正常工作。因此,很重要的一點是,運行在頁面中的代碼不應該能夠通過修改自定義元素的內部實現而意外地破壞它。Shadow DOM允許你將一個 DOM 樹附加到一個元素上,并且使該樹的內部對于在頁面中運行的 JavaScript 和 CSS 是隱藏的。

為了搞清Shadow DOM的機制,我們需要先厘清幾個概念:

1.Shadow DOM: 是一種依附于文檔原有節點的子 DOM,具有封裝性。

2.Light DOM: 指原生的DOM節點,可以通過常規的API訪問。Light DOM和Shadom DOM常常一起出現。這也是很有意思的一個比喻。一明一暗,燈下有影子。

3.Shadow Trees:Shadow DOM的樹形結構。一般地,在Shadow Trees的節點不能直接被外部JavaScript的API和選擇器訪問到,但是瀏覽器會對這些節點做渲染。

4.Shadow Host:Shadow DOM所依附的DOM節點。

5.Shadow Root:Shadow Trees的根節點。外部JavaScript如果希望對Shadow Dom進行訪問,通常會借助Shadow Root。

6.Shadow Boundary:Shadow Tree的邊界,是JavaScript訪問、CSS選擇器訪問的分界點。

7.content:指原本存在于Light DOM 結構中,被標簽添加到影子 DOM 中的節點。自Chrome 53以后,content標簽被棄用,轉而使用template和slot標簽。

8.distributed nodes:指原本位于Light DOM,但被content或template+slot添加到Shadow DOM 中的節點。

9.template:一致標簽。類似我們經常用的<script type='tpl'>,它不會被解析為dom樹的一部分,template的內容可以被塞入到Shadow DOM中并且反復利用,在template中可以設置style,但只對這個template中的元素有效。

10.slot:與template合用的標簽,用于在template中預留顯示坑位。

下面這幅圖,顯示了這些概念之間的關系:

7e65ae86c1250124bbce05b7f03a1a94.png

了解了Shadow DOM的概念,我們就可以利用Shadow Dom做一些事情了。de649d72083cf6206d8c16f670f1554f.png

這里注意下{mode: 'open'},此后通過div.shadowRoot即可拿到sr的實例。sr可以使用一般的JavaScript API來做相關的操作。

如果這里采用{mode: 'closed'},則此時div.shadowRoot為null。外部不可能再拿到sr的實例。此時外部很難操作到sr下的Shadow DOM,僅可以依靠Shadow內部的元素來進行操作。

下面是操作Shadow DOM樣式的幾種方法:

1.在Shadow DOM內部來操作Shadow Host的樣式。

:host 允許你選擇并樣式化 Shadow Tree所寄宿的元素

576ffe54f0477f0659a04fd5c7d7b1a7.png

2.跨越Shadow Boundary的樣式::part()

對于::part,在允許樣式定義的Shadow DOM,給屬性part賦值,樣式選擇器可以使用::part(屬性值)即可實現指定樣式,這與之前不同的是,Shadow Dom元素知道外界可能會對其某些元素進行變化,是可以控制變化范圍的。需要注意的是,在::part()選擇器后,子代選擇器無效。如你不能使用::part(foo) span。

24c296b0963a514bf4e3beef4205bb02.png?

::part()選擇器自Chrome73開始支持。之前的版本,可以考慮^和^^選擇器,^和^^選擇Shadow DOM在最新版本已經無效。

三、?與現代前端框架的關系

從之前的內容我們可以看到,Web Components標準中有若干內容與現代前端框架有異曲同工的感覺。同時,現代前端框架在設計時或多或少會參考Web Components的標準。VueJS的創始人尤雨溪曾明確表示過Vue的模版設計部分遵照了Web Components的標準。這也為以后瀏覽器能力逐漸增強,前端框架減負,提供了可能。

同時,現在大多數的前端框架都提供了和Web Components組件共存的機制。以Vue為例,官方更是提供了將Vue組件編譯為Web Components自主自定元素方案和自主自定元素轉化為Vue組件的工具鏈。

直接用Web Components標準撰寫的組件,原則上不需要經過預編譯環節,可以直接運行于瀏覽器,理論上會比其他前端框架性能有一定的優勢。但是,由于該標準提供的API較原始,需要做進一步封裝才能更好的使用。同時,標準缺乏對現今流行的MVVM的支持,使得前端框架在數據驅動開發模式上仍有用武之地。

Shadow Dom等標準的進展,客觀上也使得前端微服務模式慢慢成型,使得qiankun等前端解決方案有了落地的基石。

四、?結語

本文我們介紹了Web Components標準的主要技術點。應該注意到的是,標準還在不斷演化過程中,各家瀏覽器的支持也在不斷完善。我們期待,不久的將來,藉由瀏覽器原生支持的組件化方案,能夠大放光彩。

文內鏈接

[1].https://github.com/taisuke-j/progress-ring-component

[2].https://docs.microsoft.com/en-us/previous-versions/aa918246(v=msdn.10)

[3].https://www.slideshare.net/slideshow/xml-binding-language-20/155196#5

[4].https://jsbin.com/qorohov/8/edit?html,js,console,output

[5]. https://jsbin.com/qorohov/23/edit?html,output

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/37520.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/37520.shtml
英文地址,請注明出處:http://en.pswp.cn/web/37520.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

小程序、APP對接廣告聯盟進行廣告變現有什么區別?

小程序VS APP對接廣告聯盟有什么區別&#xff1f; 開發完成的小程序對接廣告聯盟廣告變現&#xff0c;開發完成的APP對接廣告聯盟有什么區別&#xff1f; 首先小程序對接廣告聯盟&#xff0c;無論是微信小程序還是抖音小程序都只支持對接單一的廣告聯盟接入。抖音小程序只支持…

【監控】監控平臺部署 Prometheus+Grafana

在 macOS 上部署 Grafana 和 Prometheus 來監控 Java 服務是一個非常實用的操作。以下是詳細的步驟&#xff0c;包括如何安裝和配置 Prometheus、Grafana 以及在 Java 服務中集成 Prometheus 的客戶端庫來收集指標數據。 1. 安裝 Prometheus 1.1 使用 Homebrew 安裝 Promethe…

簡單分享項目內如何快速自動生成自己的庫和更新 requirements.txt

當開發Python項目時&#xff0c;requirements.txt文件被用來清單所有所需的Python包及其版本。這個文件對于在不同環境中安裝和管理項目依賴特別方便&#xff0c;無論是在生產環境、開發環境或者CI/CD流程中。 要自動創建和更新requirements.txt文件&#xff0c;有幾種常見的方…

深入剖析 @Autowired 和 @Resource 在 Spring 中的區別

在 Spring 框架中&#xff0c;Autowired 和 Resource 是兩個常用的注解&#xff0c;用于實現依賴注入。盡管它們都能達到將依賴對象注入到目標 bean 的目的&#xff0c;但在細節上存在一些顯著的差異。本文將深入探討這兩個注解的區別&#xff0c;并結合 Spring 源碼進行分析&a…

vision mamba

Mamba 成功的關鍵在于采用了 Selective Scan Space State Sequential Model&#xff08;S6 模型&#xff09;。是用于解決自然語言處理&#xff08;NLP&#xff09;任務。與 transformer中注意力機制不同&#xff0c;Mamba的S6 將 1D 向量中的每個元素&#xff08;例如文本序列…

現代信息檢索筆記(二)——布爾檢索

目錄 信息檢索概述 IR vs數據庫: 結構化vs 非結構化數據 結構化數據 非結構化數據 半結構化數據 傳統信息檢索VS現代信息檢索 布爾檢索 倒排索引 一個例子 建立詞項&#xff08;可以是字、詞、短語、一句話&#xff09;-文檔的關聯矩陣。 關聯向量 檢索效果的評價 …

如何在Sklearn Pipeline中運行CatBoost

介紹 CatBoost的一大特點是可以很好的處理類別特征&#xff08;Categorical Features&#xff09;。當我們將其結合到Sklearn的Pipeline中時&#xff0c;會發生如下報錯&#xff1a; _catboost.CatBoostError: data is numpy array of floating point numerical type, it mea…

python-期末代碼復習

import numpy as np import pandas as pd import matplotlib.pyplot as plt import warningswarnings.filterwarnings(actionignore) plt.rcParams[font.sans-serif][SimHei] plt.rcParams[axes.unicode_minus] False你提供的這兩行代碼是Python編程語言中用于設置matplotlib庫…

大淘客api實現多多進寶的商品查詢PHP版

大家好&#xff0c;我是網創有方&#xff0c;今天教大家如何使用大淘客的api實現拼多多商品詳情信息查詢。這里用到的多多進寶&#xff0c;如果沒有多多進寶的&#xff0c;先去多多進寶注冊個賬號吧&#xff01; 第一步&#xff1a;進入大淘客官方創建應用&#xff0c;并且下載…

【PyQt5】一文向您詳細介紹 QLineEdit() 的作用

【PyQt5】一文向您詳細介紹 QLineEdit() 的作用 下滑即可查看博客內容 &#x1f308; 歡迎蒞臨我的個人主頁 &#x1f448;這里是我靜心耕耘深度學習領域、真誠分享知識與智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主簡介&#xff1a;985高校的普通本碩&…

2239. 找到最接近 0 的數字

給你一個長度為 n 的整數數組 nums &#xff0c;請你返回 nums 中最 接近 0 的數字。如果有多個答案&#xff0c;請你返回它們中的 最大值 。 示例 1&#xff1a; 輸入&#xff1a;nums [-4,-2,1,4,8] 輸出&#xff1a;1 解釋&#xff1a; -4 到 0 的距離為 |-4| 4 。 -2 到…

開發一個微信小程序需要用到哪些技術?

開發一個微信小程序需要用到以下幾種技術&#xff1a; 1. 基礎技術 HTML: 用于定義小程序的頁面結構。CSS: 用于頁面的樣式設計。JavaScript: 用于實現頁面的交互功能。 2. 微信小程序專用技術 WXML&#xff08;WeiXin Markup Language&#xff09;: 類似于HTML&#xff0c…

計量校準溫度儀表的常見分類有哪些?

溫度儀表在計量校準中&#xff0c;可以說是比較常見的儀器&#xff0c;而溫度儀器因為用于校準的場景很多&#xff0c;應用的場合不同&#xff0c;也是有著很多不同的分類&#xff0c;今天就簡單為大家介紹一些溫度儀表的細分分類。 溫度儀表根據測溫的方式不同&#xff0c;可以…

2024華為OD機試真題- 電腦病毒感染-(C++/Python)-C卷D卷-200分

2024華為OD機試題庫-(C卷+D卷)-(JAVA、Python、C++) 題目描述 一個局域網內有很多臺電腦,分別標注為 0 ~ N-1 的數字。相連接的電腦距離不一樣,所以感染時間不一樣,感染時間用 t 表示。 其中網絡內一臺電腦被病毒感染,求其感染網絡內所有的電腦最少需要多長時間。如果…

Laravel Activity Log操作日志擴展包

Laravel Activity Log操作日志擴展包 簡介 Laravel Action Logs操作日志記錄Laravel Activity Log 很多數據管理員都想記錄他們用戶的所有活躍記錄。這個包可以很方便的記錄你的用戶何時何地的創建、更新實體的記錄。外加&#xff0c;現在這個包還可以記錄多個版本的實體間數…

【基礎篇】第3章 索引與文檔操作

在Elasticsearch的世界里&#xff0c;索引是存儲數據的地方&#xff0c;文檔則是索引中的基本單位&#xff0c;包含具體的數據信息。本章將深入探討索引和文檔操作的基礎&#xff0c;從創建到管理&#xff0c;為高效數據處理奠定基礎。 3.1 索引概念與創建 3.1.1 索引、類型與…

PyTorch之nn.Module與nn.functional用法區別

文章目錄 1. nn.Module2. nn.functional2.1 基本用法2.2 常用函數 3. nn.Module 與 nn.functional3.1 主要區別3.2 具體樣例&#xff1a;nn.ReLU() 與 F.relu() 參考資料 1. nn.Module 在PyTorch中&#xff0c;nn.Module 類扮演著核心角色&#xff0c;它是構建任何自定義神經網…

【Spring Boot 源碼學習】初識 ConfigurableEnvironment

《Spring Boot 源碼學習系列》 初識 ConfigurableEnvironment 一、引言二、主要內容2.1 Environment2.1.1 配置文件&#xff08;profiles&#xff09;2.1.2 屬性&#xff08;properties&#xff09; 2.2 ConfigurablePropertyResolver2.2.1 屬性類型轉換配置2.2.2 占位符配置2.…

wxss和css有什么區別?

WXSS&#xff08;WeiXin Style Sheets&#xff09;和CSS&#xff08;Cascading Style Sheets&#xff09;在功能和應用上有很多相似之處&#xff0c;但針對微信小程序的特殊需求&#xff0c;WXSS對CSS進行了一些擴展和修改。以下是WXSS和CSS之間的主要區別&#xff1a; 尺寸單…

Mybatis實現流程

一&#xff0c;UserDAO 接口定義 首先&#xff0c;定義 UserDAO接口&#xff0c;包含 getList()方法,定義類型為List<User>&#xff1a; package dao;import model.User; import java.util.List;public interface UserDAO {List<User> getList(); }二&#xff0c…