日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
WebComponents是個(gè)什么樣的東西

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

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

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

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

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

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

Custom Elements

概述

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

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

registerElement

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

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

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

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

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

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

 
 
  1.   
 

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

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

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

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

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

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

createdCallback

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

  • attachedCallback
    元素插入到 document 時(shí)觸發(fā)。
  • detachedCallback
  • 元素從 document 中移除時(shí)觸發(fā),可能會(huì)用于做類似 destroy 之類的事情。

  • attributeChangedCallback
    元素屬性變化時(shí)觸發(fā),可以用于從外到內(nèi)的通信。外部通過(guò)修改元素的屬性來(lái)讓內(nèi)部獲取相關(guān)的數(shù)據(jù)并且執(zhí)行對(duì)應(yīng)的操作。

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

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

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

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

要留意上述代碼執(zhí)行之后才能使用

擴(kuò)展原有元素

其實(shí),如果我們需要一個(gè)按鈕,完全不需要重新自定義一個(gè)元素,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. hello world

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

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

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

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

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

和最新版的區(qū)別

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

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

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

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

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

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

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

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

HTML Imports

概述

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

我們最常見(jiàn)的引入一個(gè) css 文件的方式是:

 
 

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

 
 

HTMLLinkElement

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

  • 該 link 不是用來(lái) import 一個(gè) HTML 的。
  • 該 link 元素不在 document 中。

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

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

阻塞式

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

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

document

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

如果我們要獲取 import 的 HTML 的 document 的話,得這么來(lái):

 
 
  1. const d = document.currentScript.ownerDocument

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

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

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

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

HTML Templates

概述

這個(gè)東西很簡(jiǎn)單,用過(guò) handlebars 的人都知道有這么一個(gè)東西:

 
 
  1.  

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

以后可以這么寫了:

 
 
  1.   ...
  2.  

接口和應(yīng)用

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

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

 
 
  1.   
  2.     Homework
  3.   
  4.     

    Smile!

  5.     
  6.  

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

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

我們接下來(lái)看看重磅的 Shadow DOM。

Shadow DOM

概述

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

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

看下在 chrome 它會(huì)是咋樣的:

我們可以通過(guò) createShadowRoot() 來(lái)給一個(gè)元素節(jié)點(diǎn)創(chuàng)建 Shadow Root,這些元素類型必須是下邊列表的其中一個(gè),否則會(huì)拋出 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,來(lái)自文檔:https://www.w3.org/TR/2014/WD...。最新的文檔 API 已經(jīng)調(diào)整為 attachShadow()。

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

簡(jiǎn)單的使用如下:

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

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

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

在這里附上一個(gè)文檔,里邊有詳細(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 繼承而來(lái)的屬性和方法外,還多了另外兩個(gè)屬性:

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

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

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

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

slot

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

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

 
 
  1.  

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

 
 
  1.   hello
  2.   test
  3.  

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

 
 
  1.   
  2.   test
  3.  

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

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

 
 
  1.  

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

 
 
  1.   
  2.   test

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

CSS 相關(guān)

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

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

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

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

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

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

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

文檔中提供了一個(gè)例子:

 
 
  1.   <"shadow tree">
  2.     ...
  •   
  • 在這個(gè) shadow tree 內(nèi)部的樣式代碼中,會(huì)有這樣的結(jié)果:

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

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

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

     
     
    1.    <"shadow tree">
    2.      
    3.        ...
    4.      
  •      ...
  •    
  •  
  • 對(duì)于上述這一段代碼的 HTML 結(jié)構(gòu),在 Shadow DOM 外部的樣式代碼中,會(huì)是這樣的:

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

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

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

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

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

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

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

    Web Components

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

     
     

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

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

     
     
    1.   
    2.     
    3.     
    4.     
    5.   
    6.   
    7.     
    8.       
      •         
      • Home
      •         
      • About
      •       
    9.     
    10.   

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

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

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

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

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

    最后,再啰嗦一句,Web Components 個(gè)人覺(jué)得還是未來(lái)發(fā)展趨勢(shì),所以才有了這個(gè)文章。


    本文題目:WebComponents是個(gè)什么樣的東西
    URL標(biāo)題:http://www.dlmjj.cn/article/ccepcpd.html