摘要:若自定義元素標簽名稱不可用則摒棄。總之,自定義元素讓開發者的代碼更易理解和維護,并分割為小型,可復用及可封裝的模塊。被稱為自定義元素接口,雖然現在仍然可用,但是已經被棄用并被認為是糟糕的實現。
原文請查閱這里,略有刪減,本文采用知識共享署名 4.0 國際許可協議共享,BY Troland。
這是 JavaScript 工作原理第十九章。
概述在 前述文章中,我們介紹了 Shadow DOM 接口和一些其它概念,而這些都是網頁組件的組成部分。網頁組件背后的思想即通過創建顆粒化,模塊化和可復用的元素來擴展 HTML 內置功能。這是一個已經被所有主流瀏覽器兼容的相對嶄新的 W3C 標準且可以被用在生產環境之中,雖然不兼容的瀏覽器需要使用墊片庫(將在隨后的章節中進行討論)。
正如開發者所知,瀏覽器為構建網站和網頁程序提供了一些重要的開發工具。我們所說的 HTML,CSS 和 JavaScript 即開發者使用 HTML 來構建結構,CSS 進行樣式化然后使用 JavaScript 來讓頁面動起來。然而,在網頁組件出現之前,把 JavaScript 腳本和 HTML 結構組合起來并非易事。
本文將闡述網頁組件的基石-自定義元素。總之,開發者可以使用自定義元素接口來創建包含 JavaScript 邏輯和樣式的自定義元素(正如名稱的字面意思)。許多開發者會把自定義元素和 shadow DOM 混為一談。但是,他們是完全不同的概念且它們互補而不是可以相互替代的。
一些框架(比如 Angular,React) 試圖通過引進其自有概念來解決同樣的問題。開發者可以把自定義元素和 Angular 的指令或者 React 組件進行對比。然而,自定義元素是瀏覽器原生的且只需要原生 JavaScript,HTML 和 CSS。當然了,這并不意味著它可以取代一個典型的 JavaScript 框架。現代框架不僅僅為開發者提供模仿自定義元素行為的能力。因此,可以同時使用框架和自定義元素。
接口在深入了解之前,讓我們先大概快速瀏覽一下接口的內容。全局 customElements 對象為開發者提供了一些方法:
define(tagName, constructor, options) -創建一個新的自定義元素。
包含三個參數:自定義元素的可用標簽名稱,自定義元素類定義及選項參數對象。目前僅支持一個選項參數:extends 指定想要擴展的 HTML 內置元素名稱的字符串。用來創建定制化內置元素。
get(tagName) -若元素已經定義則返回自定義元素的構造函數否則返回 undefined。只有一個參數:自定義元素的可用標簽名稱。
whenDefined(tagName)-返回一個 promise 對象,當定義自定義元素即解析。若元素已定義則立即進行解析。若自定義元素標簽名稱不可用則摒棄 promise。只有一個參數:自定義元素的可用標簽名稱。
如何創建自定義元素創建自定義元素實際上就是小菜一碟。開發者只需要做兩件事:創建擴展 HTMLElement 類元素的類定義,然后以合適的名稱注冊元素。
class MyCustomElement extends HTMLElement { constructor() { super(); // … } // … } customElements.define("my-custom-element", MyCustomElement);
或者如你所愿,可以使用匿名類以防止弄亂當前作用域
customElements.define("my-custom-element", class extends HTMLElement { constructor() { super(); // … } // … });
從以上例子可見,使用 customElements.define(...) 方法注冊自定義元素。
自定義元素所解決的問題實際上,問題是啥?嵌套 DIV 是問題之一。嵌套 Div 是啥?在現代網頁程序中這是一個非常常見的現象,開發者會使用多個嵌套塊狀元素(div 互相嵌套之類)。
…
因為瀏覽器可以在頁面上正常進行渲染,所以使用了這樣的嵌套結構。但是,這會使得 HTML 不具可讀性且難以維護。
因此,例如假設有如下組件:
那么傳統 HTML 結構類似如下:
但想象下如果可以使用類似如下代碼:
要我說,第二個示例清爽多了。第二個示例更具可維護性,可讀性且對于瀏覽器和開發者更加合理。更加簡潔。
另一個問題即可復用性。作為開發者,不僅僅要書寫可運行的代碼還得寫出可維護代碼。書寫可維護代碼即能夠輕易地復用代碼片段而不是重復地復制粘貼。
我將會給出一個簡單的示例而你就會明白。假設有如下元素:
若需要在其它地方使用這段代碼,開發者需要再次書寫相同的 HTML 結構。現在,想象 一下需要稍微修改一下這些元素。開發者需要找出每個代碼需要修改的地方,然后一遍遍地做出同樣的修改。太惡心了。。。
若使用如下碼豈不會更好?
現代網頁程序不僅僅只有靜態 HTML。開發者需要做交互。這就需要 JavaScript。一般來說,開發者需要做的即創建一些元素然后在上面監聽事件以響應用戶輸入。點擊,拖拽或者懸浮事件等等。
var myDiv = document.querySelector(".my-custom-element"); myDiv.addEventListener("click", () => { myDiv.innerHTML = " I have been clicked "; });
I have not been clicked yet.
使用自定義元素接口可以把所有的邏輯封裝進元素自身。以下代碼可以實現和上面代碼一樣的功能:
class MyCustomElement extends HTMLElement { constructor() { super(); var self = this; self.addEventListener("click", () => { self.innerHTML = " I have been clicked "; }); } } customElements.define("my-custom-element", MyCustomElement);
I have not been clicked yet
咋一看上去,自定義元素技術需要書寫更多的 JavaScript 代碼。但是在實際程序中,創建不需復用的單一組件的情況是很少見的。一個典型的現代網頁程序的重要特征即大多數元素都是動態創建的。那么,開發者就需要分別處理使用 JavaScript 動態添加元素或者使用 HTML 結構中預定義內容。那么可以使用自定義元素來實現這些功能。
總之,自定義元素讓開發者的代碼更易理解和維護,并分割為小型,可復用及可封裝的模塊。
要求在創建自定義元素之前,開發者需要遵守如下特殊規則:
名稱必須包含一個破折號 - 。這樣 HTML 解析器就可以把自定義元素和內置元素區分開來。這樣可以保證不會和內置元素出現命名沖突的問題(不管是現在或者將來當添加其它元素的時候)。比如,
不允許重復注冊標簽名稱。重復注冊標簽名稱會導致瀏覽器拋出 DOMException 錯誤。不可以覆蓋已注冊自定義元素。
自定義元素不可以自關閉。HTML 解析器只允許一小撮內置元素可以自關閉(比如
let myCustomElementTemplate = document.querySelector("#my-custom-element-template"); class MyCustomElement extends HTMLElement { // ... constructor() { super(); let shadowRoot = this.attachShadow({mode: "open"}); shadowRoot.appendChild(myCustomElementTemplate.content.cloneNode(true)); } // ... });
那么現在,我們在自定義元素里面使用了 shadow DOM 和 模板,創建了一個元素,該元素作用域和其它元素隔絕且把 HTML 結構和 JavaScript 邏輯完美地隔離開來。
樣式化那么,我們講解了 HTML 和 JavaScript,現在還剩下 CSS。顯然,需要樣式化元素。開發者可以在 shadow DOM 中添加樣式但是用戶如何從外部樣式化元素呢?答案很簡單-只需要和一般的內置元素一樣寫樣式即可。
my-custom-element { border-radius: 5px; width: 30%; height: 50%; // ... }
請注意外部定義的樣式比元素內部定義的樣式優先級高,外部樣式會覆蓋掉元素內定義的樣式。
開發者需要明白有時候頁面渲染,然后會在某些時刻會發現無樣式內容閃爍(FOUC)。開發者可以通過為未定義組件定義樣式及當元素已定義的時候使用一些動畫過渡效果。使用 :defined 選擇器來達成這一效果。
my-button:not(:defined) { height: 20px; width: 50px; opacity: 0; }未知元素對比未定義自定義元素
HTML 規范非常靈活且允許開發者任意聲明標簽。若不被瀏覽器解析則會解析為 HTMLUnknownElement。
var element = document.createElement("thisElementIsUnknown"); if (element instanceof HTMLUnknownElement) { console.log("The selected element is unknown"); }
但是這并不適用于自定義元素。還記得討論定義自定義元素時候的特殊命名規則嗎?原因是因為當瀏覽器發現一個自定義元素的名稱有效的時候,瀏覽器會把它解析為 HTMLElement ,然后瀏覽器會把它看作一個未定義的自定義元素。
var element = document.createElement("this-element-is-undefined"); if (element instanceof HTMLElement) { console.log("The selected element is undefined but not unknown"); }
在視覺上, HTMLElement 和 HTMLUnknownElement 可能沒啥不同,但是需要注意其它地方。解析器會區別對待這兩種元素。具有有效自定義名稱的元素會被看作擁有自定義元素實現。在定義實現細節之前該自定義元素會被看成一個空 div 元素。而一個未定義元素沒有實現任何內置元素的任何方法或屬性。
瀏覽器兼容custom elements 第一版是在 Chrome 36+ 中引入的。被稱為自定義元素接口 v0,雖然現在仍然可用,但是已經被棄用并被認為是糟糕的實現。若想要學習 v0 版,可以閱讀這篇文章。從 Chrome 54 和 Safari 10.1(雖然只有部分支持) 開始支持自定義元素接口 v1,微軟 Edge 還處于其原型設計階段而 Mozilla 從 v50 開始支持,但默認不支持需要顯式啟用。目前只有 webkit 瀏覽器完全支持。然而,如上所述,可以使用墊片庫兼容到包括 IE11 在內的所有瀏覽器。
檢測可用性通過檢查 window 對象中的 customElements 屬性是否可用來檢查瀏覽器是否支持自定義元素。
const supportsCustomElements = "customElements" in window; if (supportsCustomElements) { // 可以使用自定義元素接口 }
否則需要使用墊片庫:
function loadScript(src) { return new Promise(function(resolve, reject) { const script = document.createElement("script"); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } // Lazy load the polyfill if necessary. if (supportsCustomElements) { // 瀏覽器原生支持自定義元素 } else { loadScript("path/to/custom-elements.min.js").then(_ => { // 加載自定義元素墊片 }); }
總之,網頁組件標準中的自定義元素為開發者提供了如下功能:
把 JavaScript 和 CSS 樣式整合入 HTML 元素
允許開發者擴展已有的 HTML 元素(內置和其它自定義元素)
不需要其它庫或者框架的支持。只需要原生 JavaScript,HTML 和 CSS 還有可選的墊片庫來支持舊瀏覽器。
可以和其它網頁組件功能無縫銜接(shadow DOM,模板,插槽等)。
和瀏覽器開發者工具緊密集成在一起。
使用已知的可訪問功能
總之,自定義元素和開發者已經使用過的組件技術并沒有什么大的不同。它只讓開發網頁程序過程更加便攜的另一種方式。那么,它讓更快地構建非常復雜的程序成為可能。
參考資料:
https://developers.google.com...
https://www.html5rocks.com/en...
https://github.com/w3c/webcom...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102256.html
摘要:前端每周清單半年盤點之與篇前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。與求同存異近日,宣布將的構建工具由遷移到,引發了很多開發者的討論。 前端每周清單半年盤點之 React 與 ReactNative 篇 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為...
摘要:本文轉載自眾成翻譯譯者文藺鏈接原文今年的頂級舉措之一是為我們的用戶提供一個更好的瀏覽體驗。這意味著保持最少的。這些組件有全局的,網站速度信標現場速度信標套件,試驗的庫文件,以及統計模塊等。它們在發布前要經歷嚴格的回歸測試,這就會增加延時。 本文轉載自:眾成翻譯譯者:文藺鏈接:http://www.zcfy.cc/article/912原文:http://www.ebaytechblog...
摘要:五六月份推薦集合查看最新的請點擊集前端最近很火的框架資源定時更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風荷舉。家住吳門,久作長安旅。五月漁郎相憶否。小楫輕舟,夢入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請::點擊::集web前端最近很火的vue2框架資源;定時更新,歡迎 Star 一下。 蘇...
閱讀 3192·2021-11-23 10:09
閱讀 2057·2021-10-26 09:51
閱讀 975·2021-10-09 09:44
閱讀 3898·2021-10-08 10:04
閱讀 2742·2021-09-22 15:14
閱讀 3619·2021-09-22 15:02
閱讀 1035·2021-08-24 10:03
閱讀 1719·2019-12-27 12:14