成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Web Components是個什么樣的東西

開發(fā) 前端
Web Components 包括了四個部分:Custom Elements、HTML Imports、HTML Templates、Shadow DOM這四部分有機(jī)地組合在一起,才是 Web Components。

[[170777]]

前端組件化這個主題相關(guān)的內(nèi)容已經(jīng)火了很久很久,angular 剛出來時的 Directive 到 angular2 的 components,還有 React 的components 等等,無一不是前端組件化的一種實(shí)現(xiàn)和探索,但是提上議程的 Web Components 標(biāo)準(zhǔn)是個怎樣的東西,相關(guān)的一些框架或者類庫,如 React,Angular2,甚至是 x-tag,polymer 現(xiàn)在實(shí)現(xiàn)的組件化的東西和 Web Components 標(biāo)準(zhǔn)差別在哪里?我花時間努力地把現(xiàn)有的 W3C Web Components 文檔看了下,然后堅強(qiáng)地寫下這些記錄。

首先我們需要知道,Web Components 包括了四個部分:

  • Custom Elements
  • HTML Imports
  • HTML Templates
  • Shadow DOM

這四部分有機(jī)地組合在一起,才是 Web Components。

可以用自定義的標(biāo)簽來引入組件是前端組件化的基礎(chǔ),在頁面引用 HTML 文件和 HTML 模板是用于支撐編寫組件視圖和組件資源管理,而 Shadow DOM 則是隔離組件間代碼的沖突和影響。

下邊分別是每一部分的筆記內(nèi)容。

Custom Elements

概述

Custom Elements 顧名思義,是提供一種方式讓開發(fā)者可以自定義 HTML 元素,包括特定的組成,樣式和行為。支持 Web Components 標(biāo)準(zhǔn)的瀏覽器會提供一系列 API 給開發(fā)者用于創(chuàng)建自定義的元素,或者擴(kuò)展現(xiàn)有元素。

這一項(xiàng)標(biāo)準(zhǔn)的草案還處于不穩(wěn)定的狀態(tài),時有更新,API 還會有所變化,下邊的筆記以 Cutsom Elements 2016.02.26 這個版本為準(zhǔn),因?yàn)樵谧钚碌?chrome 瀏覽器已經(jīng)是可以工作的了,這樣可以使用 demo 來做嘗試,最后我會再簡單寫一下最新文檔和這個的區(qū)別。

registerElement

首先,我們可以嘗試在 chrome 控制臺輸入 HTMLInputElement,可以看到是有這么一個東西的,這個理解為 input DOM 元素實(shí)例化時的構(gòu)造函數(shù),基礎(chǔ)的是 HTMLElement。

Web Components 標(biāo)準(zhǔn)提出提供這么一個接口:

  1. document.registerElement('x-foo', { 
  2.   prototype: Object.create(HTMLElement.prototype, { 
  3.     createdCallback: {       
  4.       value: function() { ... } 
  5.     }, 
  6.     ... 
  7.   }) 
  8. })  

你可以使用 document.registerElement 來注冊一個標(biāo)簽,標(biāo)準(zhǔn)中為了提供 namesapce 的支持,防止沖突,規(guī)定標(biāo)簽類型(也可以理解為名字)需要使用 - 連接。同時,不能是以下這一些:

  • annotation-xml
  • color-profile
  • font-face
  • font-face-src
  • font-face-uri
  • font-face-format
  • font-face-name
  • missing-glyph

第二個參數(shù)是標(biāo)簽相關(guān)的配置,主要是提供一個 prototype,這個原型對象是以 HTMLElement 等的原型為基礎(chǔ)創(chuàng)建的對象。然后你便可以在 HTML 中去使用自定義的標(biāo)簽。如:

  1. <div> 
  2.   <x-foo></x-foo> 
  3. </div>  

是不是嗅到了 React 的味道?好吧,React 說它自己主要不是做這個事情的。

生命周期和回調(diào)

在這個 API 的基礎(chǔ)上,Web Components 標(biāo)準(zhǔn)提供了一系列控制自定義元素的方法。我們來一一看下:

一個自定義元素會經(jīng)歷以下這些生命周期:

  • 注冊前創(chuàng)建
  • 注冊自定義元素定義
  • 在注冊后創(chuàng)建元素實(shí)例
  • 元素插入到 document 中
  • 元素從 document 中移除
  • 元素的屬性變化時

這個是很重要的內(nèi)容,開發(fā)者可以在注冊新的自定義元素時指定對應(yīng)的生命周期回調(diào)來為自定義元素添加各種自定義的行為,這些生命周期回調(diào)包括了:

createdCallback

自定義元素注冊后,在實(shí)例化之后會調(diào)用,通常多用于做元素的初始化,如插入子元素,綁定事件等。

  • attachedCallback
    元素插入到 document 時觸發(fā)。
  • detachedCallback
  • 元素從 document 中移除時觸發(fā),可能會用于做類似 destroy 之類的事情。
  • attributeChangedCallback
    元素屬性變化時觸發(fā),可以用于從外到內(nèi)的通信。外部通過修改元素的屬性來讓內(nèi)部獲取相關(guān)的數(shù)據(jù)并且執(zhí)行對應(yīng)的操作。

這個回調(diào)在不同情況下有對應(yīng)不同的參數(shù):

  • 設(shè)置屬性時,參數(shù)列表是:屬性名稱,null,值,命名空間
  • 修改屬性時,參數(shù)列表是:屬性名稱,舊值,新值,命名空間
  • 刪除屬性時,參數(shù)列表是:屬性名稱,舊值,null,命名空間

好了,就上邊了解到的基礎(chǔ)上,假設(shè)我們要創(chuàng)建一個自定義的 button-hello 按鈕,點(diǎn)擊時會 alert('hello world'),代碼如下:

  1. document.registerElement('button-hello', { 
  2.   prototype: Object.create(HTMLButtonElement.prototype, { 
  3.     createdCallback: { 
  4.       value: function createdCallback() { 
  5.         this.innerHTML = '<button>hello world</button>' 
  6.         this.addEventListener('click', () => { 
  7.           alert('hello world'
  8.         }) 
  9.       } 
  10.     } 
  11.   }) 
  12. })  

要留意上述代碼執(zhí)行之后才能使用 <button-hello></button-hello>

擴(kuò)展原有元素

其實(shí),如果我們需要一個按鈕,完全不需要重新自定義一個元素,Web Components 標(biāo)準(zhǔn)提供了一種擴(kuò)展現(xiàn)有標(biāo)簽的方式,把上邊的代碼調(diào)整一下: 

  1. document.registerElement('button-hello', { 
  2.   prototype: Object.create(HTMLButtonElement.prototype, { 
  3.     createdCallback: { 
  4.       value: function createdCallback() { 
  5.         this.addEventListener('click', () => { 
  6.           alert('hello world'
  7.         }) 
  8.       } 
  9.     } 
  10.   }), 
  11.   extends: 'button' 
  12. })  

然后在 HTML 中要這么使用:

  1. <button is="button-hello">hello world</button> 

使用 is 屬性來聲明一個擴(kuò)展的類型,看起來也蠻酷的。生命周期和自定義元素標(biāo)簽的保持一致。

當(dāng)我們需要多個標(biāo)簽組合成新的元素時,我們可以使用自定義的元素標(biāo)簽,但是如果只是需要在原有的 HTML 標(biāo)簽上進(jìn)行擴(kuò)展的話,使用 is 的這種元素擴(kuò)展的方式就好。

原有的 createElement 和 createElementNS,在 Web Components 標(biāo)準(zhǔn)中也擴(kuò)展成為支持元素擴(kuò)展,例如要創(chuàng)建一個 button-hello:

  1. const hello = document.createElement('button''button-hello'

標(biāo)準(zhǔn)文檔中還有很多細(xì)節(jié)上的內(nèi)容,例如接口的參數(shù)說明和要求,回調(diào)隊(duì)列的實(shí)現(xiàn)要求等,這些更多是對于實(shí)現(xiàn)這個標(biāo)準(zhǔn)的瀏覽器開發(fā)者的要求,這里不做詳細(xì)描述了,內(nèi)容很多,有興趣的自行查閱:Cutsom Elements 2016.02.26。

和最新版的區(qū)別

前邊我提到說文檔的更新變化很快,截止至我寫這個文章的時候,最新的文檔是這個:Custom Elements 2016.07.21。

細(xì)節(jié)不做描述了,講講我看到的最大變化,就是向 ES6 靠攏。大致有下邊三點(diǎn):

  • 從原本的擴(kuò)展 prototype 來定義元素調(diào)整為建議使用 class extends 的方式
  • 注冊自定義元素接口調(diào)整,更加方便使用,傳入 type 和 class 即可
  • 生命周期回調(diào)調(diào)整,createdCallback 直接用 class 的 constructor

前兩個點(diǎn),我們直接看下代碼,原本的代碼按照新的標(biāo)準(zhǔn),應(yīng)該調(diào)整為:

  1. class ButtonHelloElement extends HTMLButtonElement { 
  2.   constructor() { 
  3.     super() 
  4.  
  5.     this.addEventListener('click', () => { 
  6.       alert('hello world'
  7.     }) 
  8.   } 
  9.  
  10. customElements.define('button-hello', ButtonHelloElement, { extends: 'button' })  

從代碼上看會感覺更加 OO,編寫上也比原本要顯得方便一些,原本的生命周期回調(diào)是調(diào)整為新的:

  • constructor in class 作用相當(dāng)于原本的 createdCallback
  • connectedCallback 作用相當(dāng)于 attachedCallback
  • disconnectedCallback 作用相當(dāng)于 detachedCallback
  • adoptedCallback 使用 document.adoptNode(node) 時觸發(fā)
  • attributeChangedCallback 和原本保持一致

connect 事件和插入元素到 document 有些許區(qū)別,主要就是插入元素到 document 時,元素狀態(tài)會變成 connected,這時會觸發(fā) connectedCallback,disconnect 亦是如此。

HTML Imports

概述

HTML Imports 是一種在 HTMLs 中引用以及復(fù)用其他的 HTML 文檔的方式。這個 Import 很漂亮,可以簡單理解為我們常見的模板中的include 之類的作用。

我們最常見的引入一個 css 文件的方式是:

  1. <link rel="stylesheet" href="/css/master.css"

Web Components 現(xiàn)在提供多了一個這個:

  1. <link rel="import" href="/components/header.html"

HTMLLinkElement

原本的 link 標(biāo)簽在添加了 HTML Import 之后,多了一個只讀的 import 屬性,當(dāng)出現(xiàn)下邊兩種情況時,這個屬性為 null:

  • 該 link 不是用來 import 一個 HTML 的。
  • 該 link 元素不在 document 中。

否則,這個屬性會返回一個表示引入的 HTML 文件的文檔對象,類似于 document。比如說,在上邊的代碼基礎(chǔ)上,可以這樣做:

  1. const link = document.querySelector('link[rel=import]'
  2. const header = link.import; 
  3.  
  4. const pulse = header.querySelector('div.logo');  

阻塞式

我們要知道的是,默認(rèn)的 link 加載是阻塞式的,除非你給他添加一個 async 標(biāo)識。

阻塞式從某種程度上講是有必要的,當(dāng)你 improt 的是一個完整的自定義組件并且需要在主 HTML 中用標(biāo)簽直接使用時,非阻塞的就會出現(xiàn)錯誤了,因?yàn)闃?biāo)簽還沒有被注冊。

document

有一點(diǎn)值得留意的是,在 import 的 HTML 中,我們編寫的 script 里邊的 document 是指向 import 這個 HTML 的主 HTML 的 document。

如果我們要獲取 import 的 HTML 的 document 的話,得這么來:

  1. const d = document.currentScript.ownerDocument 

這樣設(shè)計是因?yàn)?import 進(jìn)來的 HTML 需要用到主 HTML 的 document。例如我們上邊提到的 registerElement。

在一個被 import 的 HTML 文件中使用下邊三個方法會拋出一個 InvalidStateError 異常:

  • document.open()
  • document.write()
  • document.close()

對于 HTML Import,標(biāo)準(zhǔn)文檔中還有很大一部分內(nèi)容是關(guān)于多個依賴加載的處理算法的,在這里就不詳述了,有機(jī)會的話找時間再開篇談,這些內(nèi)容是需要瀏覽器去實(shí)現(xiàn)的。

HTML Templates

概述

這個東西很簡單,用過 handlebars 的人都知道有這么一個東西:

  1. <script id="template" type="text/x-handlebars-template"
  2.   ... 
  3. </script>  

其他模板引擎也有類似的東西,那么 HTML Templates 便是把這個東西官方標(biāo)準(zhǔn)化,提供了一個 template 標(biāo)簽來存放以后需要但是暫時不渲染的 HTML 代碼。

以后可以這么寫了:

  1. <template id="template"
  2.   ... 
  3. </template>  

接口和應(yīng)用

template 元素有一個只讀的屬性 content,用于返回這個 template 里邊的內(nèi)容,返回的結(jié)果是一個 DocumentFragment。

具體是如何使用的,直接參考官方給出的例子:

  1. <!doctype html> 
  2. <html lang="en"
  3.   <head> 
  4.     <title>Homework</title> 
  5.   <body> 
  6.     <template id="template"><p>Smile!</p></template> 
  7.     <script> 
  8.       let num = 3; 
  9.       const fragment = document.getElementById('template').content.cloneNode(true); 
  10.       while (num-- > 1) { 
  11.         fragment.firstChild.before(fragment.firstChild.cloneNode(true)); 
  12.         fragment.firstChild.textContent += fragment.lastChild.textContent; 
  13.       } 
  14.       document.body.appendChild(fragment); 
  15.     </script> 
  16. </html>  

使用 DocumentFragment 的 clone 方法以 template 里的代碼為基礎(chǔ)創(chuàng)建一個元素節(jié)點(diǎn),然后你便可以操作這個元素節(jié)點(diǎn),最后在需要的時候插入到 document 中特定位置便可以了。

Template 相關(guān)的東西不多,而且它現(xiàn)在已經(jīng)是納入生效的 標(biāo)準(zhǔn)文檔 中了。

我們接下來看看重磅的 Shadow DOM。

Shadow DOM

概述

Shadow DOM 好像提出好久了,最本質(zhì)的需求是需要一個隔離組件代碼作用域的東西,例如我組件代碼的 CSS 不能影響其他組件之類的,而 iframe 又太重并且可能有各種奇怪問題。

可以這么說,Shadow DOM 旨在提供一種更好地組織頁面元素的方式,來為日趨復(fù)雜的頁面應(yīng)用提供強(qiáng)大支持,避免代碼間的相互影響。

看下在 chrome 它會是咋樣的: 

我們可以通過 createShadowRoot() 來給一個元素節(jié)點(diǎn)創(chuàng)建 Shadow Root,這些元素類型必須是下邊列表的其中一個,否則會拋出 NotSupportedError 異常。

  • 自定義的元素
  • article
  • aside
  • blockquote
  • body
  • div
  • header, footer
  • h1, h2, h3, h4, h5, h6
  • nav
  • p
  • section
  • span

createShadowRoot() 是現(xiàn)在 chrome 實(shí)現(xiàn)的 API,來自文檔:https://www.w3.org/TR/2014/WD...。最新的文檔 API 已經(jīng)調(diào)整為 attachShadow()。

返回的 Shadow Root 對象從 DocumentFragment 繼承而來,所以可以使用相關(guān)的一些方法,例如shadowRoot.getElementById('id') 來獲取 Shadow DOM 里邊的元素。

簡單的使用如下:

  1. const div = document.getElementById('id'
  2. const shadowRoot = div.createShadowRoot() 
  3. const span = document.createElement('span'
  4.  
  5. span.textContent = 'hello world' 
  6. shadowRoot.appendChild(span)  

在這里,我把這個 div 成為是這個 Shadow DOM 的 宿主元素,下邊的內(nèi)容會延續(xù)使用這個稱呼。

Shadow DOM 本身就為了代碼隔離而生,所以在 document 上使用 query 時,是沒法獲取到 Shadow DOM 里邊的元素的,需要在 Shadow Root 上做 query 才行。

在這里附上一個文檔,里邊有詳細(xì)的關(guān)于新的標(biāo)準(zhǔn)和現(xiàn)在 blink 引擎實(shí)現(xiàn)的 Shadow DOM 的區(qū)別,官方上稱之為 v0 和 v1:Shadow DOM v1 in Blink。

API

Shadow Root 除了從 DocumentFragment 繼承而來的屬性和方法外,還多了另外兩個屬性:

  • host 只讀屬性,用來獲取這個 Shadow Root 所屬的元素
  • innerHTML 用來獲取或者設(shè)置里邊的 HTML 字符串,和我們常用的 element.innerHTML 是一樣的

另外,在最新的標(biāo)準(zhǔn)文檔中,元素除了上邊提到的 attachShadow 方法之外,還多了三個屬性:

  • assignedSlot 只讀,這個元素如果被分配到了某個 Shadow DOM 里邊的 slot,那么會返回這個對應(yīng)的 slot 元素
  • slot 元素的 slot 屬性,用來指定 slot 的名稱
  • shadowRoot 只讀,元素下面對應(yīng)的 Shadow Root 對象

slot 是什么?接著看下邊的內(nèi)容,看完下一節(jié)的最后一部分就會明白上述內(nèi)容和 slot 相關(guān)的兩個 API 有什么作用。

slot

slot 提供了在使用自定義標(biāo)簽的時候可以傳遞子模板給到內(nèi)部使用的能力,可以簡單看下 Vue 的一個例子。

我們先來看下現(xiàn)在 chrome 可以跑的 v0 版本,這一個版本是提供了一個 content 標(biāo)簽,代表了一個占位符,并且有一個 select 屬性用來指定使用哪些子元素。

  1. <!-- component input-toggle template --> 
  2. <input type="checkbox"></input> 
  3. <content select=".span"></content>  

自定義的元素里邊的子元素代碼是這樣的:

  1. <input-toggle name="hello"
  2.   <span>hello</span> 
  3.   <span class="span">test</span> 
  4. </input-toggle>  

那么展現(xiàn)的結(jié)果會和下邊的代碼是一樣的:

  1. <input-toggle name="hello"
  2.   <input type="checkbox"></input> 
  3.   <span class="span">test</span> 
  4. </input-toggle>  

這里只是說展現(xiàn)結(jié)果,實(shí)際上,input-toggle 里邊應(yīng)該是創(chuàng)建了一個 Shadow DOM,然后 content 標(biāo)簽引用了目標(biāo)的 span 內(nèi)容,在 chrome 看是這樣的: 

 然后,是最新標(biāo)準(zhǔn)中的 slot 使用方式,直接上例子代碼:

  1. <!-- component input-toggle template --> 
  2. <input type="checkbox"></input> 
  3. <slot name="text"></slot>  

在自定義的元素標(biāo)簽是這么使用 slot 的:

  1. <input-toggle name="hello"
  2.   <input type="checkbox"></input> 
  3.   <span class="span" slot="text">test</span> 
  4. </input-toggle> 

 

通過 slot="text" 的屬性來讓元素內(nèi)部的 slot 占位符可以引用到這個元素,多個元素使用這個屬性也是可以的。這樣子我們便擁有了使用標(biāo)簽是從外部傳 template 給到自定義元素的內(nèi)部去使用,而且具備指定放在那里的能力。

CSS 相關(guān)

因?yàn)橛?Shadow DOM 的存在,所以在 CSS 上又添加了很多相關(guān)的東西,其中一部分還是屬于討論中的草案,命名之類的可能會有變更,下邊提及的內(nèi)容主要來自文檔:Shadow DOM in CSS scoping 1,很多部分在 chrome 是已經(jīng)實(shí)現(xiàn)的了,有興趣可以寫 demo 試試。

因?yàn)?Shadow DOM 很大程度上是為了隔離樣式作用域而誕生的,主文檔中的樣式規(guī)則不對 Shadow DOM 里的子文檔生效,子文檔中的樣式規(guī)則也不影響外部文檔。

但不可避免的,在某些場景下,我們需要外部可以控制 Shadow DOM 中樣式,如提供一個組件給你,有時候你會希望可以自定義它內(nèi)部的一些樣式,同時,Shadow DOM 中的代碼有時候可能需要能夠控制其所屬元素的樣式,甚至,組件內(nèi)部可以定義上邊提到的通過 slot 傳遞進(jìn)來的 HTML 的樣式。所以呢,是的,CSS 選擇器中添加了幾個偽類,我們一一來看下它們有什么作用。

在閱讀下邊描述的時候,請留意一下選擇器的代碼是在什么位置的,Shadow DOM 內(nèi)部還是外部。

:host 用于在 Shadow DOM 內(nèi)部選擇到其宿主元素,當(dāng)它不是在 Shadow DOM 中使用時,便匹配不到任意元素。

在 Shadow DOM 中的 * 選擇器是無法選擇到其宿主元素的。

:host( <selector> ) 括號中是一個選擇器,這個可以理解為是一個用于兼容在主文檔和 Shadow DOM 中使用的方法,當(dāng)這個選擇器在 Shadow DOM 中時,會匹配到括號中選擇器對應(yīng)的宿主元素,如果不是,則匹配括號中選擇器能夠匹配到的元素。

文檔中提供了一個例子:

  1. <x-foo class="foo"
  2.   <"shadow tree"
  3.     <div class="foo">...</div> 
  4.   </> 
  5. </x-foo> 

 

在這個 shadow tree 內(nèi)部的樣式代碼中,會有這樣的結(jié)果:

  • :host 匹配 <x-foo> 元素
  • x-foo 匹配不到元素
  • .foo 只匹配到 <div> 元素
  • .foo:host 匹配不到元素
  • :host(.foo) 匹配 <x-foo> 元素

:host-context( <selector> ),用于在 Shadow DOM 中來檢測宿主元素的父級元素,如果宿主元素或者其祖先元素能夠被括號中的選擇器匹配到的話,那么這個偽類選擇器便匹配到這個 Shadow DOM 的宿主元素。個人理解是用于在宿主元素外部元素滿足一定的條件時添加樣式。

::shadow 這個偽類用于在 Shadow DOM 外部匹配其內(nèi)部的元素,而 /deep/ 這個標(biāo)識也有同樣的作用,我們來看一個例子:

  1. <x-foo> 
  2.    <"shadow tree"
  3.      <div> 
  4.        <span id="not-top">...</span> 
  5.      </div> 
  6.      <span id="top">...</span> 
  7.    </> 
  8.  </x-foo> 

 

對于上述這一段代碼的 HTML 結(jié)構(gòu),在 Shadow DOM 外部的樣式代碼中,會是這樣的:

  • x-foo::shadow > span 可以匹配到 #top 元素
  • #top 匹配不到元素
  • x-foo /deep/ span 可以匹配到 #not-top 和 #top 元素

/deep/ 這個標(biāo)識的作用和我們的 > 選擇器有點(diǎn)類似,只不過它是匹配其對應(yīng)的 Shadow DOM 內(nèi)部的,這個標(biāo)識可能還會變化,例如改成 >> 或者 >>> 之類的,個人感覺, >> 會更舒服。

最后一個,用于在 Shadow DOM 內(nèi)部調(diào)整 slot 的樣式,在我查閱的這個文檔中,暫時是以 chrome 實(shí)現(xiàn)的為準(zhǔn),使用 ::content 偽類,不排除有更新為 ::slot 的可能性。我們看一個例子來了解一下,就算名稱調(diào)整了也是差不多的用法:

  1. <x-foo> 
  2.   <div id="one" class="foo">...</div> 
  3.   <div id="two">...</div> 
  4.   <div id="three" class="foo"
  5.     <div id="four">...</div> 
  6.   </div> 
  7.   <"shadow tree"
  8.     <div id="five">...</div> 
  9.     <div id="six">...</div> 
  10.     <content select=".foo"></content> 
  11.   </"shadow tree"
  12. </x-foo>  

在 Shadow DOM 內(nèi)部的樣式代碼中,::content div 可以匹配到 #one,#three 和 #four,留意一下 #two 為什么沒被匹配到,因?yàn)樗鼪]有被 content 元素選中,即不會進(jìn)行引用。如果更換成 slot 的 name 引用的方式亦是同理。

層疊規(guī)則,按照這個文檔的說法,對于兩個優(yōu)先級別一樣的 CSS 聲明,沒有帶 !important 的,在 Shadow DOM 外部聲明的優(yōu)先級高于在 Shadow DOM 內(nèi)部的,而帶有 !important 的,則相反。個人認(rèn)為,這是提供給外部一定的控制能力,同時讓內(nèi)部可以限制一定的影響范圍。

繼承方面相對簡單,在 Shadow DOM 內(nèi)部的頂級元素樣式從宿主元素繼承而來。

至此,Web Components 四個部分介紹結(jié)束了,其中有一些細(xì)節(jié),瀏覽器實(shí)現(xiàn)細(xì)節(jié),還有使用上的部分細(xì)節(jié),是沒有提及的,因?yàn)樵敿?xì)記錄的話,還會有很多東西,內(nèi)容很多。當(dāng)使用過程中有疑問時可以再次查閱標(biāo)準(zhǔn)文檔,有機(jī)會的話會再完善這個文章。下一部分會把這四個內(nèi)容組合起來,整體看下 Web Components 是怎么使用的。

Web Components

Web Components 總的來說是提供一整套完善的封裝機(jī)制來把 Web 組件化這個東西標(biāo)準(zhǔn)化,每個框架實(shí)現(xiàn)的組件都統(tǒng)一標(biāo)準(zhǔn)地進(jìn)行輸入輸出,這樣可以更好推動組件的復(fù)用。結(jié)合上邊各個部分的內(nèi)容,我們整合一起來看下應(yīng)該怎么使用這個標(biāo)準(zhǔn)來實(shí)現(xiàn)我們的組件:

  1. <!-- components/header.html --> 
  2. <template id=""
  3. <style> 
  4. ::content li { 
  5.   display: inline-block; 
  6.   padding: 20px 10px; 
  7. </style> 
  8. <content select="ul"></content> 
  9. </template> 
  10. <script> 
  11. (function() { 
  12.   const element = Object.create(HTMLInputElement.prototype) 
  13.   const template = document.currentScript.ownerDocument.querySelector('template'
  14.  
  15.   element.createdCallback = function() { 
  16.     const shadowRoot = this.createShadowRoot() 
  17.     const clone = document.importNode(template.content, true
  18.     shadowRoot.appendChild(clone) 
  19.  
  20.     this.addEventListener('click'function(event) { 
  21.       console.log(event.target.textContent) 
  22.     }) 
  23.   } 
  24.  
  25.   document.registerElement('test-header', { prototype: element }) 
  26. })() 
  27. </script> 

 

這是一個簡單的組件的例子,用于定義一個 test-header,并且給傳遞進(jìn)來的子元素 li 添加了一些組件內(nèi)部的樣式,同時給組件綁定了一個點(diǎn)擊事件,來打印點(diǎn)擊目標(biāo)的文本內(nèi)容。

看下如何在一個 HTML 文件中引入并且使用一個組件:

  1. <!-- index.html --> 
  2. <!DOCTYPE html> 
  3. <html> 
  4.   <head> 
  5.     <meta charset="utf-8"
  6.     <title></title> 
  7.  
  8.     <link rel="import" href="components/header.html"
  9.   </head> 
  10.   <body> 
  11.     <test-header> 
  12.       <ul> 
  13.         <li>Home</li> 
  14.         <li>About</li> 
  15.       </ul> 
  16.     </test-header> 
  17.   </body> 
  18. </html> 

 

一個 import 的 <link> 把組件的 HTML 文件引用進(jìn)來,這樣會執(zhí)行組件中的腳本,來注冊一個 test-header 元素,這樣子我們便可以在主文檔中使用這個元素的標(biāo)簽。

上邊的例子是可以在 chrome 正常運(yùn)行的。

所以,根據(jù)上邊簡單的例子可以看出,各個部分的內(nèi)容是有機(jī)結(jié)合在一起,Custom Elements 提供了自定義元素和標(biāo)簽的能力,template 提供組件模板,import 提供了在 HTML 中合理引入組件的方式,而 Shadow DOM 則處理組件間代碼隔離的問題。

不得不承認(rèn),Web Components 標(biāo)準(zhǔn)的提出解決了一些問題,必須交由瀏覽器去處理的是 Shadow DOM,在沒有 Shadow DOM 的瀏覽器上實(shí)現(xiàn)代碼隔離的方式多多少少有缺陷。個人我覺得組件化的各個 API 不夠簡潔易用,依舊有 getElementById 這些的味道,但是交由各個類庫去簡化也可以接受,而 import 功能上沒問題,但是加載多個組件時性能問題還是值得商榷,標(biāo)準(zhǔn)可能需要在這個方面提供更多給瀏覽器的指引,例如是否有可能提供一種單一請求加載多個組件 HTML 的方式等。

在現(xiàn)在的移動化趨勢中,Web Components 不僅僅是 Web 端的問題,越來越多的開發(fā)者期望以 Web 的方式去實(shí)現(xiàn)移動應(yīng)用,而多端復(fù)用的實(shí)現(xiàn)漸漸是以組件的形式鋪開,例如 React Native 和 Weex。所以 Web Components 的標(biāo)準(zhǔn)可能會影響到多端開發(fā) Web 化的一個模式和發(fā)展。

最后,再啰嗦一句,Web Components 個人覺得還是未來發(fā)展趨勢,所以才有了這個文章。

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2015-04-08 10:40:09

2019-01-11 10:39:24

軟件架構(gòu)虛擬空間機(jī)器人

2020-04-07 08:05:51

程序員互聯(lián)網(wǎng)職業(yè)

2016-12-07 18:10:08

邊緣計算

2013-06-26 10:49:09

云端大腦科技技術(shù)

2022-06-13 23:30:27

代碼詞匯高質(zhì)量

2010-08-02 13:30:34

移動開發(fā)移動開發(fā)平臺

2024-02-26 09:13:35

WebComponents開源項(xiàng)目

2009-08-02 22:32:44

綜合布線系統(tǒng)

2022-03-01 07:00:00

AI架構(gòu)師人工智能

2020-03-19 15:21:57

智慧城市藝術(shù)社會

2019-07-08 17:34:29

共享辦公ideaPod文印

2017-04-06 15:00:38

編程語言

2020-04-22 14:15:13

5G網(wǎng)絡(luò)技術(shù)

2020-09-23 08:55:16

交換機(jī)配置網(wǎng)絡(luò)vlan

2019-05-13 15:45:29

程序員面試招聘

2012-06-18 09:33:03

云計算IBM惠普

2022-10-30 15:03:25

人工智能倉庫管理機(jī)器人

2013-12-25 09:07:24

微軟鮑爾默諾基亞

2009-10-26 13:36:10

BSM
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 日韩在线观看一区 | 国产精品不卡 | 欧美aaaaaaaaaa| 欧美一区二区在线 | 日韩一区二区三区视频 | 亚洲狠狠| 日韩免费一区 | 午夜免费视频观看 | 国产91观看| 国产偷录叫床高潮录音 | 亚洲国产免费 | 亚洲一区亚洲二区 | 色婷婷综合久久久中文字幕 | 日韩无| 毛片在线免费 | 综合婷婷| 91久久久久久久 | 久久成人国产精品 | 中文字幕精品一区 | 亚洲免费一区 | 久久精品| 在线日韩欧美 | 国产精品久久久久久久久免费 | 伊人色综合久久天天五月婷 | 女生羞羞网站 | 日日夜夜草 | 午夜精品久久久久久久星辰影院 | 在线日韩av电影 | 日韩精品专区在线影院重磅 | 欧美综合一区二区三区 | 成年人在线视频 | 成人二区 | 欧美最猛性xxxxx亚洲精品 | 久久国产精品久久久久久久久久 | 中日av| 欧美精品一区在线观看 | 日本三级电影免费观看 | www.天天操 | 日韩免费1区二区电影 | 日本高清精品 | 国产成人精品一区二区三区四区 |