亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

自定義元素探秘及構(gòu)建可復(fù)用組件最佳實(shí)踐

CoorChice / 576人閱讀

摘要:若自定義元素標(biāo)簽名稱不可用則摒棄??傊?,自定義元素讓開(kāi)發(fā)者的代碼更易理解和維護(hù),并分割為小型,可復(fù)用及可封裝的模塊。被稱為自定義元素接口,雖然現(xiàn)在仍然可用,但是已經(jīng)被棄用并被認(rèn)為是糟糕的實(shí)現(xiàn)。

原文請(qǐng)查閱這里,略有刪減,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。

這是 JavaScript 工作原理第十九章。

概述

在 前述文章中,我們介紹了 Shadow DOM 接口和一些其它概念,而這些都是網(wǎng)頁(yè)組件的組成部分。網(wǎng)頁(yè)組件背后的思想即通過(guò)創(chuàng)建顆粒化,模塊化和可復(fù)用的元素來(lái)擴(kuò)展 HTML 內(nèi)置功能。這是一個(gè)已經(jīng)被所有主流瀏覽器兼容的相對(duì)嶄新的 W3C 標(biāo)準(zhǔn)且可以被用在生產(chǎn)環(huán)境之中,雖然不兼容的瀏覽器需要使用墊片庫(kù)(將在隨后的章節(jié)中進(jìn)行討論)。

正如開(kāi)發(fā)者所知,瀏覽器為構(gòu)建網(wǎng)站和網(wǎng)頁(yè)程序提供了一些重要的開(kāi)發(fā)工具。我們所說(shuō)的 HTML,CSS 和 JavaScript 即開(kāi)發(fā)者使用 HTML 來(lái)構(gòu)建結(jié)構(gòu),CSS 進(jìn)行樣式化然后使用 JavaScript 來(lái)讓頁(yè)面動(dòng)起來(lái)。然而,在網(wǎng)頁(yè)組件出現(xiàn)之前,把 JavaScript 腳本和 HTML 結(jié)構(gòu)組合起來(lái)并非易事。

本文將闡述網(wǎng)頁(yè)組件的基石-自定義元素??傊?,開(kāi)發(fā)者可以使用自定義元素接口來(lái)創(chuàng)建包含 JavaScript 邏輯和樣式的自定義元素(正如名稱的字面意思)。許多開(kāi)發(fā)者會(huì)把自定義元素和 shadow DOM 混為一談。但是,他們是完全不同的概念且它們互補(bǔ)而不是可以相互替代的。

一些框架(比如 Angular,React) 試圖通過(guò)引進(jìn)其自有概念來(lái)解決同樣的問(wèn)題。開(kāi)發(fā)者可以把自定義元素和 Angular 的指令或者 React 組件進(jìn)行對(duì)比。然而,自定義元素是瀏覽器原生的且只需要原生 JavaScript,HTML 和 CSS。當(dāng)然了,這并不意味著它可以取代一個(gè)典型的 JavaScript 框架。現(xiàn)代框架不僅僅為開(kāi)發(fā)者提供模仿自定義元素行為的能力。因此,可以同時(shí)使用框架和自定義元素。

接口

在深入了解之前,讓我們先大概快速瀏覽一下接口的內(nèi)容。全局 customElements 對(duì)象為開(kāi)發(fā)者提供了一些方法:

define(tagName, constructor, options) -創(chuàng)建一個(gè)新的自定義元素。

包含三個(gè)參數(shù):自定義元素的可用標(biāo)簽名稱,自定義元素類(lèi)定義及選項(xiàng)參數(shù)對(duì)象。目前僅支持一個(gè)選項(xiàng)參數(shù):extends 指定想要擴(kuò)展的 HTML 內(nèi)置元素名稱的字符串。用來(lái)創(chuàng)建定制化內(nèi)置元素。

get(tagName) -若元素已經(jīng)定義則返回自定義元素的構(gòu)造函數(shù)否則返回 undefined。只有一個(gè)參數(shù):自定義元素的可用標(biāo)簽名稱。

whenDefined(tagName)-返回一個(gè) promise 對(duì)象,當(dāng)定義自定義元素即解析。若元素已定義則立即進(jìn)行解析。若自定義元素標(biāo)簽名稱不可用則摒棄 promise。只有一個(gè)參數(shù):自定義元素的可用標(biāo)簽名稱。

如何創(chuàng)建自定義元素

創(chuàng)建自定義元素實(shí)際上就是小菜一碟。開(kāi)發(fā)者只需要做兩件事:創(chuàng)建擴(kuò)展 HTMLElement 類(lèi)元素的類(lèi)定義,然后以合適的名稱注冊(cè)元素。

class MyCustomElement extends HTMLElement {
  constructor() {
    super();
    // …
  }

  // …
}

customElements.define("my-custom-element", MyCustomElement);

或者如你所愿,可以使用匿名類(lèi)以防止弄亂當(dāng)前作用域

customElements.define("my-custom-element", class extends HTMLElement {
  constructor() {
    super();
    // …
  }

  // …
});

從以上例子可見(jiàn),使用 customElements.define(...) 方法注冊(cè)自定義元素。

自定義元素所解決的問(wèn)題

實(shí)際上,問(wèn)題是啥?嵌套 DIV 是問(wèn)題之一。嵌套 Div 是啥?在現(xiàn)代網(wǎng)頁(yè)程序中這是一個(gè)非常常見(jiàn)的現(xiàn)象,開(kāi)發(fā)者會(huì)使用多個(gè)嵌套塊狀元素(div 互相嵌套之類(lèi))。

因?yàn)闉g覽器可以在頁(yè)面上正常進(jìn)行渲染,所以使用了這樣的嵌套結(jié)構(gòu)。但是,這會(huì)使得 HTML 不具可讀性且難以維護(hù)。

因此,例如假設(shè)有如下組件:

那么傳統(tǒng) HTML 結(jié)構(gòu)類(lèi)似如下:

 
 
 
 

但想象下如果可以使用類(lèi)似如下代碼:


  
    
    
    
    
  

要我說(shuō),第二個(gè)示例清爽多了。第二個(gè)示例更具可維護(hù)性,可讀性且對(duì)于瀏覽器和開(kāi)發(fā)者更加合理。更加簡(jiǎn)潔。

另一個(gè)問(wèn)題即可復(fù)用性。作為開(kāi)發(fā)者,不僅僅要書(shū)寫(xiě)可運(yùn)行的代碼還得寫(xiě)出可維護(hù)代碼。書(shū)寫(xiě)可維護(hù)代碼即能夠輕易地復(fù)用代碼片段而不是重復(fù)地復(fù)制粘貼。

我將會(huì)給出一個(gè)簡(jiǎn)單的示例而你就會(huì)明白。假設(shè)有如下元素:

若需要在其它地方使用這段代碼,開(kāi)發(fā)者需要再次書(shū)寫(xiě)相同的 HTML 結(jié)構(gòu)?,F(xiàn)在,想象 一下需要稍微修改一下這些元素。開(kāi)發(fā)者需要找出每個(gè)代碼需要修改的地方,然后一遍遍地做出同樣的修改。太惡心了。。。

若使用如下碼豈不會(huì)更好?

現(xiàn)代網(wǎng)頁(yè)程序不僅僅只有靜態(tài) HTML。開(kāi)發(fā)者需要做交互。這就需要 JavaScript。一般來(lái)說(shuō),開(kāi)發(fā)者需要做的即創(chuàng)建一些元素然后在上面監(jiān)聽(tīng)事件以響應(yīng)用戶輸入。點(diǎn)擊,拖拽或者懸浮事件等等。

var myDiv = document.querySelector(".my-custom-element");

myDiv.addEventListener("click", () => {
  myDiv.innerHTML = " I have been clicked ";
});
I have not been clicked yet.

使用自定義元素接口可以把所有的邏輯封裝進(jìn)元素自身。以下代碼可以實(shí)現(xiàn)和上面代碼一樣的功能:

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

咋一看上去,自定義元素技術(shù)需要書(shū)寫(xiě)更多的 JavaScript 代碼。但是在實(shí)際程序中,創(chuàng)建不需復(fù)用的單一組件的情況是很少見(jiàn)的。一個(gè)典型的現(xiàn)代網(wǎng)頁(yè)程序的重要特征即大多數(shù)元素都是動(dòng)態(tài)創(chuàng)建的。那么,開(kāi)發(fā)者就需要分別處理使用 JavaScript 動(dòng)態(tài)添加元素或者使用 HTML 結(jié)構(gòu)中預(yù)定義內(nèi)容。那么可以使用自定義元素來(lái)實(shí)現(xiàn)這些功能。

總之,自定義元素讓開(kāi)發(fā)者的代碼更易理解和維護(hù),并分割為小型,可復(fù)用及可封裝的模塊。

要求

在創(chuàng)建自定義元素之前,開(kāi)發(fā)者需要遵守如下特殊規(guī)則:

名稱必須包含一個(gè)破折號(hào) - 。這樣 HTML 解析器就可以把自定義元素和內(nèi)置元素區(qū)分開(kāi)來(lái)。這樣可以保證不會(huì)和內(nèi)置元素出現(xiàn)命名沖突的問(wèn)題(不管是現(xiàn)在或者將來(lái)當(dāng)添加其它元素的時(shí)候)。比如, 是正確的而 myCustomElement 則不然。

不允許重復(fù)注冊(cè)標(biāo)簽名稱。重復(fù)注冊(cè)標(biāo)簽名稱會(huì)導(dǎo)致瀏覽器拋出 DOMException 錯(cuò)誤。不可以覆蓋已注冊(cè)自定義元素。

自定義元素不可以自關(guān)閉。HTML 解析器只允許一小撮內(nèi)置元素可以自關(guān)閉(比如

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));
  }

  // ...
});

那么現(xiàn)在,我們?cè)谧远x元素里面使用了 shadow DOM 和 模板,創(chuàng)建了一個(gè)元素,該元素作用域和其它元素隔絕且把 HTML 結(jié)構(gòu)和 JavaScript 邏輯完美地隔離開(kāi)來(lái)。

樣式化

那么,我們講解了 HTML 和 JavaScript,現(xiàn)在還剩下 CSS。顯然,需要樣式化元素。開(kāi)發(fā)者可以在 shadow DOM 中添加樣式但是用戶如何從外部樣式化元素呢?答案很簡(jiǎn)單-只需要和一般的內(nèi)置元素一樣寫(xiě)樣式即可。

my-custom-element {
  border-radius: 5px;
  width: 30%;
  height: 50%;
  // ...
}

請(qǐng)注意外部定義的樣式比元素內(nèi)部定義的樣式優(yōu)先級(jí)高,外部樣式會(huì)覆蓋掉元素內(nèi)定義的樣式。

開(kāi)發(fā)者需要明白有時(shí)候頁(yè)面渲染,然后會(huì)在某些時(shí)刻會(huì)發(fā)現(xiàn)無(wú)樣式內(nèi)容閃爍(FOUC)。開(kāi)發(fā)者可以通過(guò)為未定義組件定義樣式及當(dāng)元素已定義的時(shí)候使用一些動(dòng)畫(huà)過(guò)渡效果。使用 :defined 選擇器來(lái)達(dá)成這一效果。

my-button:not(:defined) {
  height: 20px;
  width: 50px;
  opacity: 0;
}
未知元素對(duì)比未定義自定義元素

HTML 規(guī)范非常靈活且允許開(kāi)發(fā)者任意聲明標(biāo)簽。若不被瀏覽器解析則會(huì)解析為 HTMLUnknownElement。

var element = document.createElement("thisElementIsUnknown");

if (element instanceof HTMLUnknownElement) {
  console.log("The selected element is unknown");
}

但是這并不適用于自定義元素。還記得討論定義自定義元素時(shí)候的特殊命名規(guī)則嗎?原因是因?yàn)楫?dāng)瀏覽器發(fā)現(xiàn)一個(gè)自定義元素的名稱有效的時(shí)候,瀏覽器會(huì)把它解析為 HTMLElement ,然后瀏覽器會(huì)把它看作一個(gè)未定義的自定義元素。

var element = document.createElement("this-element-is-undefined");

if (element instanceof HTMLElement) {
  console.log("The selected element is undefined but not unknown");
}

在視覺(jué)上, HTMLElement 和 HTMLUnknownElement 可能沒(méi)啥不同,但是需要注意其它地方。解析器會(huì)區(qū)別對(duì)待這兩種元素。具有有效自定義名稱的元素會(huì)被看作擁有自定義元素實(shí)現(xiàn)。在定義實(shí)現(xiàn)細(xì)節(jié)之前該自定義元素會(huì)被看成一個(gè)空 div 元素。而一個(gè)未定義元素沒(méi)有實(shí)現(xiàn)任何內(nèi)置元素的任何方法或?qū)傩浴?/p> 瀏覽器兼容

custom elements 第一版是在 Chrome 36+ 中引入的。被稱為自定義元素接口 v0,雖然現(xiàn)在仍然可用,但是已經(jīng)被棄用并被認(rèn)為是糟糕的實(shí)現(xiàn)。若想要學(xué)習(xí) v0 版,可以閱讀這篇文章。從 Chrome 54 和 Safari 10.1(雖然只有部分支持) 開(kāi)始支持自定義元素接口 v1,微軟 Edge 還處于其原型設(shè)計(jì)階段而 Mozilla 從 v50 開(kāi)始支持,但默認(rèn)不支持需要顯式啟用。目前只有 webkit 瀏覽器完全支持。然而,如上所述,可以使用墊片庫(kù)兼容到包括 IE11 在內(nèi)的所有瀏覽器。

檢測(cè)可用性

通過(guò)檢查 window 對(duì)象中的 customElements 屬性是否可用來(lái)檢查瀏覽器是否支持自定義元素。

const supportsCustomElements = "customElements" in window;

if (supportsCustomElements) {
  // 可以使用自定義元素接口
}

否則需要使用墊片庫(kù):

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(_ => {
    // 加載自定義元素墊片
  });
}

總之,網(wǎng)頁(yè)組件標(biāo)準(zhǔn)中的自定義元素為開(kāi)發(fā)者提供了如下功能:

把 JavaScript 和 CSS 樣式整合入 HTML 元素

允許開(kāi)發(fā)者擴(kuò)展已有的 HTML 元素(內(nèi)置和其它自定義元素)

不需要其它庫(kù)或者框架的支持。只需要原生 JavaScript,HTML 和 CSS 還有可選的墊片庫(kù)來(lái)支持舊瀏覽器。

可以和其它網(wǎng)頁(yè)組件功能無(wú)縫銜接(shadow DOM,模板,插槽等)。

和瀏覽器開(kāi)發(fā)者工具緊密集成在一起。

使用已知的可訪問(wèn)功能

總之,自定義元素和開(kāi)發(fā)者已經(jīng)使用過(guò)的組件技術(shù)并沒(méi)有什么大的不同。它只讓開(kāi)發(fā)網(wǎng)頁(yè)程序過(guò)程更加便攜的另一種方式。那么,它讓更快地構(gòu)建非常復(fù)雜的程序成為可能。

參考資料:

https://developers.google.com...

https://www.html5rocks.com/en...

https://github.com/w3c/webcom...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/102256.html

相關(guān)文章

  • 前端每周清單半年盤(pán)點(diǎn)之 React 與 ReactNative 篇

    摘要:前端每周清單半年盤(pán)點(diǎn)之與篇前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開(kāi)發(fā)教程工程實(shí)踐深度閱讀開(kāi)源項(xiàng)目巔峰人生等欄目。與求同存異近日,宣布將的構(gòu)建工具由遷移到,引發(fā)了很多開(kāi)發(fā)者的討論。 前端每周清單半年盤(pán)點(diǎn)之 React 與 ReactNative 篇 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn);分為...

    Barry_Ng 評(píng)論0 收藏0
  • 【譯】 eBay 的速度與風(fēng)范

    摘要:本文轉(zhuǎn)載自眾成翻譯譯者文藺鏈接原文今年的頂級(jí)舉措之一是為我們的用戶提供一個(gè)更好的瀏覽體驗(yàn)。這意味著保持最少的。這些組件有全局的,網(wǎng)站速度信標(biāo)現(xiàn)場(chǎng)速度信標(biāo)套件,試驗(yàn)的庫(kù)文件,以及統(tǒng)計(jì)模塊等。它們?cè)诎l(fā)布前要經(jīng)歷嚴(yán)格的回歸測(cè)試,這就會(huì)增加延時(shí)。 本文轉(zhuǎn)載自:眾成翻譯譯者:文藺鏈接:http://www.zcfy.cc/article/912原文:http://www.ebaytechblog...

    davidac 評(píng)論0 收藏0
  • 關(guān)于Vue2一些值得推薦的文章 -- 五、六月份

    摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥(niǎo)雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門(mén),久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...

    sutaking 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<