web組件標(biāo)準(zhǔn) web components

組件的概念

組件,是數(shù)據(jù)和方法的一個(gè)封裝,其定義了一個(gè)可重用的軟件元素的功能,展示和使用,通常表現(xiàn)為一個(gè)或一組可重用的元素。

組件的特性

可拓展性:既然組件是針對(duì)某一特定功能或需求開發(fā)的,那它就必須易于開發(fā)和拓展;
封裝性:組件作為一個(gè)獨(dú)立整體供使用,應(yīng)該是對(duì)內(nèi)修改,對(duì)外封閉,只供使用,而不對(duì)使用環(huán)境產(chǎn)生副作用;
易用性:組件的目的是產(chǎn)生可重用的獨(dú)立部件,那就必須提供一種簡(jiǎn)單快捷的方式供使用。

Web Components特征

Web Components將一系列特性加入HTMLDOM規(guī)范,使得開發(fā)者可以自由創(chuàng)建在web應(yīng)用或文檔可重用的元素或部件,其由四部分組成:

HTML模板(HTML Templates):HTML內(nèi)的DOM模板,在<template>元素內(nèi)聲明。

影子DOM(Shadow DOM):組合對(duì)DOM和樣式的封裝;

HTML導(dǎo)入(HTML Imports):定義在文檔中導(dǎo)入其他HTML文檔的方式;

自定義元素(Custom Elements):定義新HTML元素的一系列API;

HTML模板

<body>
    <hello-button>hello</hello-button>
</body>
<script>
(function() {
  var HelloButtonPrototype = Object.create(HTMLElement.prototype);
  HelloButtonPrototype.who = function() {
      alert('Hello!');
  }
  HelloButtonPrototype.createdCallback = function() {
      this.addEventListener('click', function(e) {
          HelloButtonPrototype.who();
      });
  }
  document.registerElement('hello-button', {prototype: HelloButtonPrototype});
})();
</script>

影子DOM(Shadow DOM)

DOM,即文檔對(duì)象模型,是HTML文檔的一個(gè)結(jié)構(gòu)表示,以樹形結(jié)構(gòu)表示一個(gè)文檔,文檔中元素間關(guān)系按照父子,兄弟關(guān)系排列;DOM規(guī)范提供一系列API支持我們操作文檔節(jié)點(diǎn),即通常所說(shuō)的DOM API。

前面提到Web Components指封裝DOM和樣式,以組件的形式在文檔中使用,而不同于JavaScript中函數(shù)會(huì)形成一個(gè)單獨(dú)作用域,文檔DOM樹的層次結(jié)構(gòu)中是不存在局部作用域概念的,也就是說(shuō)文檔內(nèi)所有定義的樣式都對(duì)整個(gè)文檔產(chǎn)生影響,文檔中的樣式也會(huì)影響組件內(nèi)的聲明樣式,而不限定于元素所處位置,這樣顯然極大阻礙了組件的獨(dú)立性和可重用性,是必須要解決的問(wèn)題,不過(guò)不用擔(dān)心,這都已經(jīng)解決了,解決方案就是下文介紹的attachShadow()方法。

影子DOM API提供了attachShadow()方法,創(chuàng)建一個(gè)影子DOM,支持將封裝的內(nèi)容或組件作為一個(gè)獨(dú)立DOM子樹附加進(jìn)一個(gè)HTML文檔,組件內(nèi)與外部隔離,樣式互不影響,這也印證了組件開發(fā)的封裝性需求。

創(chuàng)建

要?jiǎng)?chuàng)建一個(gè)影子DOM,很簡(jiǎn)單,使用attachShadow()方法即可,而需要注意的是所有影子DOM必須和一個(gè)文檔中存在的元素(HTML內(nèi)置元素或自定義元素)綁定,才能使用:

    var frag = document.createElement('div');
    var shadowRoot = frag.attachShadow({mode: 'open'});
    // open 可以通過(guò)javascript來(lái)獲取shandow DOM 例如
    // close的話,就是不可以在外部獲取到shadow Dom 了,訪問(wèn)shadowRoot就會(huì)返回null
    shadowRoot.innerHTML = '<p>Shadow DOM Content</p>';
    
    // class寫法
    class SlotTest extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({mode: 'open'});
      }
      connectedCallback() {
    
      }
    }
    
    customElements.define('slot-test', SlotTest);

影子樹(SHADOW TREE)與影子主體(SHADOW HOST)

上文使用attachShadow()方法創(chuàng)建的元素就是一個(gè)影子DOM,而其子內(nèi)容就構(gòu)成一棵影子樹(shadow tree),而和影子DOM綁定,也就是包含該樹的文檔內(nèi)元素通常稱為影子主體(shadow host)。

template 槽位(SLOT)

    <div class="menus">
        <h2>Menus</h2>
        <slot></slot>
    </div>

使用:

    <slot-test>
        <ul>
            <li>home</li>
            <li>order</li>
            <li>about</li>
        </ul>
    </slot-test>

渲染結(jié)果:

    <div class="menus">
        <h2>Menus</h2>
        <ul>
            <li>Home</li>
            <li>order</li>
            <li>about</li>
        </ul>
    </div>

命名槽

    <div class="menus">
        <h2>Menus</h2>
        <slot name="menu"></slot>
    </div>
    <slot-test>
        <ul>
            <li>home</li>
            <li>order</li>
            <li>about</li>
        </ul>
         <ul slot="menu">
            <li>menu home</li>
            <li>menu order</li>
            <li>menu about</li>
        </ul>
    </slot-test>

渲染結(jié)果

    <div class="menus">
        <h2>Menus</h2>
        <ul>
            <li>menu home</li>
            <li>menu order</li>
            <li>menu about</li>
        </ul>
    </div>

樣式

Web Components定義的組件內(nèi)的樣式與外部環(huán)境的樣式是互不影響的,那么如何為組件設(shè)置樣式呢,依然使用<style>標(biāo)簽:

    class SlotTest extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({mode: 'open'});
        this.shadowRoot.innerHTML = `
          <style>
            div h2 {
              color: red;
            }
          </style>
          <div>
            <h2>Menus</h2>
            <slot></slot>
          </div>
        `
      }
      connectedCallback() {
    
      }
    }
    customElements.define('slot-test', SlotTest);

HTML引入(HTML Imports)

    <link rel="import" href="components.html">

自定義元素(Custom Elements)

自定義元素支持開發(fā)者定義一類新HTML元素,聲明其行為和樣式,自定義元素分兩類:

自定義標(biāo)簽元素(Autonomous custom elements):完全獨(dú)立于原始HTML元素標(biāo)簽的新標(biāo)簽元素,其所有行為需要開發(fā)者定義;

自定義內(nèi)置元素(Customized built-in):基于HTML原始元素標(biāo)簽的自定義元素,以便于使用原始元素的特性,開發(fā)者只需要定義拓展行為;

創(chuàng)建自定義標(biāo)簽元素

為了創(chuàng)建一個(gè)自定義標(biāo)簽元素,我們需要繼承HTMLELement類, 如在很多頁(yè)面我們經(jīng)常會(huì)有一鍵回到頁(yè)面頂部功能,我們創(chuàng)建一個(gè)返回頂部的組件:

    class GoTop extends HTMLElement {
      constructor() {
        super();
        this.addClick()
      }
      addClick() {
        this.addEventListener('click',function(e) {
          console.log(999);
          (function smoothscroll(){
            var currentScroll = document.documentElement.scrollTop || document.body.scrollTop;
            if (currentScroll > 0) {
                 window.requestAnimationFrame(smoothscroll);
                 window.scrollTo (0,currentScroll - (currentScroll/5));
            }
          })();
        })
      }
      connectedCallback() {
        // 首次被插入文檔DOM時(shí),被調(diào)用
        console.log(88888)
        console.log(this.getAttribute('data-name'))
      }
      disconnectedCallback() {
        // 文檔DOM中刪除時(shí),被調(diào)用
      }
      adoptedCallback() {
        // 被移動(dòng)到新的文檔時(shí),被調(diào)用
      }
      attributesChangedCallback() {
        // 元素的屬性被增刪改時(shí)執(zhí)行
      }
    }
    console.log(HTMLElement.prototype)
    customElements.define('go-top', GoTop);

生命周期函數(shù)github example:
https://github.com/mdn/web-components-examples/tree/master/life-cycle-callbacks

在需要使用該組件的頁(yè)面只需像使用正常HTML元素一樣:

    <go-top>Top</go-top>

該元素的一切樣式,行為,事件監(jiān)聽,默認(rèn)行為均需要開發(fā)者自行定義

    //帶圖片及l(fā)ink的組件
    class ImgLink extends HTMLElement {
      constructor() {
        super();
      }
      connectedCallback() {
        let src = this.getAttribute('src');
        let height = this.getAttribute('height') || '100';
        let width = this.getAttribute('width') || '100';
        // Create a shadow root
        let shadow = this.attachShadow({mode: 'open'});
        // create img
        let img = document.createElement('img');
        img.src = src;
        img.width = width; 
        img.height = height; 
        shadow.appendChild(img)
        // create a
        let link = document.createElement('a');
        link.href = this.getAttribute('url');
        link.innerText = this.getAttribute('name')
        shadow.appendChild(link)
      }
    }
    
    customElements.define('img-link', ImgLink);
    

使用

    <img-link width="100" height="100" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/javascript.png" url="http://www.w3school.com.cn/js/index.asp" name="javascript"></img-link>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容