国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

一文讀懂Web Component

開發 前端
Shadow DOM。 主要用于將 Shadow DOM 的內容與外層 document DOM 隔離,可以理解為在document中的一個子容器,放置各種組件;HTML 模板。 使用 <template> 來定義組件模板,使用 <slot> 作為插槽使用(Vuer一定不陌生)。

前言

由于最近作者在學習微前端,web component也是其中一大特性,部分微前端框架使用到,也是深入學習了一下相關的知識,分享出來。

Web Component是什么?

Web Component 實際上一系列技術的組合,主要包含 3 部分:

  • 自定義元素。 在 HTML 基礎標簽外擴展自定義標簽元素,也就是我們平時使用框架的"組件";
  • Shadow DOM。 主要用于將 Shadow DOM 的內容與外層 document DOM 隔離,可以理解為在document中的一個子容器,放置各種組件;
  • HTML 模板。 使用 <template> 來定義組件模板,使用 <slot> 作為插槽使用(Vuer一定不陌生);

在一份html文件中的一個web component看起來是這樣的:

<trace-ele name="webComponent" version="0.0.1" desc="原生態自帶隔離的組件"" data-textnode-index-1701072719744="25" data-index-1701072719744="405" data-index-len-1701072719744="405" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
  <div slot="slot-ele"" data-textnode-index-1701072719744="28" data-index-1701072719744="428" data-index-len-1701072719744="428" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>插槽內容</div" data-textnode-index-1701072719744="29" data-index-1701072719744="438" data-index-len-1701072719744="438" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
</trace-ele" data-textnode-index-1701072719744="31" data-index-1701072719744="450" data-index-len-1701072719744="450" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>

看起來很像Vue吧?接下來讓我們一個個demo學習web component。

上手

由于Web Component親和原生,因此無需其他包的依賴,一個index.html和一個index.js即可體驗學習。

我們直接寫一個html模板,文章的案例組件統稱為<trace-ele />

index.html:

<body" data-textnode-index-1701072719744="48" data-index-1701072719744="606" data-index-len-1701072719744="606" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
 <template id="trace"" data-textnode-index-1701072719744="56" data-index-1701072719744="628" data-index-len-1701072719744="628" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
      <div class="container"" data-textnode-index-1701072719744="64" data-index-1701072719744="657" data-index-len-1701072719744="657" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <img
          class="image"
          src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
          alt=""
        /" data-textnode-index-1701072719744="80" data-index-1701072719744="806" data-index-len-1701072719744="806" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <p class="title"" data-textnode-index-1701072719744="88" data-index-1701072719744="831" data-index-len-1701072719744="831" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>學習Web Component</p" data-textnode-index-1701072719744="92" data-index-1701072719744="850" data-index-len-1701072719744="850" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <p class="desc"" data-textnode-index-1701072719744="100" data-index-1701072719744="874" data-index-len-1701072719744="874" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>Web Component是微前端沙盒隔離原理的重要知識</p" data-textnode-index-1701072719744="104" data-index-1701072719744="906" data-index-len-1701072719744="906" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <p class="price"" data-textnode-index-1701072719744="112" data-index-1701072719744="931" data-index-len-1701072719744="931" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>¥25.00</p" data-textnode-index-1701072719744="116" data-index-1701072719744="941" data-index-len-1701072719744="941" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
      </div" data-textnode-index-1701072719744="120" data-index-1701072719744="953" data-index-len-1701072719744="953" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    </template" data-textnode-index-1701072719744="124" data-index-1701072719744="968" data-index-len-1701072719744="968" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    <trace-ele /" data-textnode-index-1701072719744="128" data-index-1701072719744="985" data-index-len-1701072719744="985" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    <script src="./index.js" /" data-textnode-index-1701072719744="136" data-index-1701072719744="1016" data-index-len-1701072719744="1016" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
</body" data-textnode-index-1701072719744="139" data-index-1701072719744="1023" data-index-len-1701072719744="1023" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>

這里我們寫了一個"模板"——template,并在下面聲明了<trace-ele />組件。

而實現這一切的原理在index.js中。

class Trace extends HTMLElement {
  constructor() {
    super();
    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);
    this.appendChild(cloneEle);
  }
}

customElements.define("trace-ele", Trace);

Web Component組件本質是一個類繼承于HTMLElement,當customElements.define聲明完組件后,類中的this指向于組件本身,打印結果如下:

圖片圖片

在初始化時,需要提供給組件一個空殼,并且綁定template元素的id,這樣就出現組件效果了。

圖片圖片

看到這里是不是感覺和Vue很像呢?接下來我們繼續升級組件的功能~

來點樣式吧

在上一節基礎上,給組件上點樣式,很簡單,改變index.html即可,在template中加入style:

<body" data-textnode-index-1701072719744="209" data-index-1701072719744="1590" data-index-len-1701072719744="1590" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
 <template id="trace"" data-textnode-index-1701072719744="217" data-index-1701072719744="1612" data-index-len-1701072719744="1612" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
      <div class="container"" data-textnode-index-1701072719744="225" data-index-1701072719744="1641" data-index-len-1701072719744="1641" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <img
          class="image"
          src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
          alt=""
        /" data-textnode-index-1701072719744="241" data-index-1701072719744="1790" data-index-len-1701072719744="1790" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <p class="title"" data-textnode-index-1701072719744="249" data-index-1701072719744="1815" data-index-len-1701072719744="1815" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>學習Web Component</p" data-textnode-index-1701072719744="253" data-index-1701072719744="1834" data-index-len-1701072719744="1834" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <p class="desc"" data-textnode-index-1701072719744="261" data-index-1701072719744="1858" data-index-len-1701072719744="1858" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>Web Component是微前端沙盒隔離原理的重要知識</p" data-textnode-index-1701072719744="265" data-index-1701072719744="1890" data-index-len-1701072719744="1890" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <p class="price"" data-textnode-index-1701072719744="273" data-index-1701072719744="1915" data-index-len-1701072719744="1915" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>¥25.00</p" data-textnode-index-1701072719744="277" data-index-1701072719744="1925" data-index-len-1701072719744="1925" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
      </div" data-textnode-index-1701072719744="281" data-index-1701072719744="1937" data-index-len-1701072719744="1937" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
      
      <style" data-textnode-index-1701072719744="286" data-index-1701072719744="1956" data-index-len-1701072719744="1956" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        .container {
          display: inline-flex;
          flex-direction: column;
          border-radius: 6px;
          border: 1px solid silver;
          padding: 16px;
          margin-right: 16px;
        }
        .image {
          border-radius: 6px;
        }
        .title {
          font-weight: 500;
          font-size: 16px;
          line-height: 22px;
          color: #222;
          margin-top: 14px;
          margin-bottom: 9px;
        }
        .desc {
          margin-bottom: 12px;
          line-height: 1;
          font-size: 14px;
        }
        .price {
          font-size: 14px;
        }
      </style" data-textnode-index-1701072719744="391" data-index-1701072719744="2574" data-index-len-1701072719744="2574" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    </template" data-textnode-index-1701072719744="395" data-index-1701072719744="2589" data-index-len-1701072719744="2589" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    <trace-ele /" data-textnode-index-1701072719744="399" data-index-1701072719744="2606" data-index-len-1701072719744="2606" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    <script src="./index.js" /" data-textnode-index-1701072719744="407" data-index-1701072719744="2637" data-index-len-1701072719744="2637" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
</body" data-textnode-index-1701072719744="410" data-index-1701072719744="2644" data-index-len-1701072719744="2644" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>

樣式生效:

圖片圖片

但是這里如果給一個通用標簽的樣式,就像這樣:

<body" data-textnode-index-1701072719744="416" data-index-1701072719744="2686" data-index-len-1701072719744="2686" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    <p" data-textnode-index-1701072719744="420" data-index-1701072719744="2693" data-index-len-1701072719744="2693" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>組件外的P標簽</p" data-textnode-index-1701072719744="424" data-index-1701072719744="2704" data-index-len-1701072719744="2704" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <template" data-textnode-index-1701072719744="428" data-index-1701072719744="2722" data-index-len-1701072719744="2722" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <p" data-textnode-index-1701072719744="432" data-index-1701072719744="2733" data-index-len-1701072719744="2733" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>組件中的P標簽</p" data-textnode-index-1701072719744="436" data-index-1701072719744="2744" data-index-len-1701072719744="2744" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <style" data-textnode-index-1701072719744="440" data-index-1701072719744="2759" data-index-len-1701072719744="2759" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
           p {
             color: red;
           }
            ...
            .container {}
        </style" data-textnode-index-1701072719744="455" data-index-1701072719744="2865" data-index-len-1701072719744="2865" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        </template" data-textnode-index-1701072719744="459" data-index-1701072719744="2884" data-index-len-1701072719744="2884" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
</body" data-textnode-index-1701072719744="462" data-index-1701072719744="2891" data-index-len-1701072719744="2891" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>

效果如下:

圖片圖片

可以看到組件外的p標簽也被影響了,顏色變為紅色,而在組件概念中這個樣式其實只期望作用于組件本身。這也是樣式隔離的概念,而很幸運,Web Component提供了開箱即用的樣式隔離方案。

為了不讓 <template> 里的 <style> CSS 和全局的 CSS 有沖突,我們可以將組件掛在到 Shadow Root 上,再用 Shadow Root 掛到外層的 document DOM 上,這樣就可以實現 CSS 的隔離啦:

class Trace extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: "open" });
    
    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);

    this.shadowRoot.appendChild(cloneEle);
  }
}

customElements.define("trace-ele", Trace);

從控制臺中觀察:

圖片圖片

而如果有多個組件本質其實就是在document中有多個Shadow Root。

整個DOM架構圖是這樣的:

圖片圖片

Shadow DOM 的一大優點是能將 DOM 結構、樣式、行為與 Document DOM 隔離開,非常適合做組件的封裝,因此它能成為 Web Component 的重要組成部分之一。

Props

與Vue、React一樣,Web Component也提供了父傳子的形式。

index.html:

<trace-ele name="webComponent" version="0.0.1" desc="原生態自帶隔離的組件"" data-textnode-index-1701072719744="551" data-index-1701072719744="3716" data-index-len-1701072719744="3716" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>

這里傳了3個props給組件,在組件中打印this如下:

火眼金睛的我已經找到了在組件中接受傳參的入口:

圖片圖片

做一個簡單的動態賦值:

class Trace extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({ mode: "open" });

    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);
    cloneEle.querySelector('.container " data-textnode-index-1701072719744="593" data-index-1701072719744="4043" data-index-len-1701072719744="4043" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> .title').textContent = this.getAttribute('name');
    cloneEle.querySelector('.container " data-textnode-index-1701072719744="600" data-index-1701072719744="4133" data-index-len-1701072719744="4133" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> .price').textContent = this.getAttribute('version');
    cloneEle.querySelector('.container " data-textnode-index-1701072719744="607" data-index-1701072719744="4226" data-index-len-1701072719744="4226" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> .desc').textContent = this.getAttribute('desc');

    this.shadowRoot.appendChild(cloneEle);
  }
}

customElements.define("trace-ele", Trace);

搞定~

Slot

HTML 模板的另一個好處是可以像 Vue 一樣使用 <slot>。比如,現在我們可以在這個 <trace-ele> 最下面添加一個插槽:

<body" data-textnode-index-1701072719744="632" data-index-1701072719744="4445" data-index-len-1701072719744="4445" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    <template id="trace"" data-textnode-index-1701072719744="640" data-index-1701072719744="4470" data-index-len-1701072719744="4470" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <div class="container"" data-textnode-index-1701072719744="648" data-index-1701072719744="4501" data-index-len-1701072719744="4501" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
            <p" data-textnode-index-1701072719744="652" data-index-1701072719744="4516" data-index-len-1701072719744="4516" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>組件中的P標簽</p" data-textnode-index-1701072719744="656" data-index-1701072719744="4527" data-index-len-1701072719744="4527" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
            <img
              class="image"
              src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
              alt=""
            /" data-textnode-index-1701072719744="672" data-index-1701072719744="4696" data-index-len-1701072719744="4696" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
            <p class="title"" data-textnode-index-1701072719744="680" data-index-1701072719744="4725" data-index-len-1701072719744="4725" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>學習Web Component</p" data-textnode-index-1701072719744="684" data-index-1701072719744="4744" data-index-len-1701072719744="4744" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
            <p class="desc"" data-textnode-index-1701072719744="692" data-index-1701072719744="4772" data-index-len-1701072719744="4772" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>Web Component是微前端沙盒隔離原理的重要知識</p" data-textnode-index-1701072719744="696" data-index-1701072719744="4804" data-index-len-1701072719744="4804" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
            <p class="price"" data-textnode-index-1701072719744="704" data-index-1701072719744="4833" data-index-len-1701072719744="4833" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>¥25.00</p" data-textnode-index-1701072719744="708" data-index-1701072719744="4843" data-index-len-1701072719744="4843" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
            <slot name="slot-ele"" data-textnode-index-1701072719744="716" data-index-1701072719744="4877" data-index-len-1701072719744="4877" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">></slot" data-textnode-index-1701072719744="719" data-index-1701072719744="4884" data-index-len-1701072719744="4884" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        </div" data-textnode-index-1701072719744="723" data-index-1701072719744="4898" data-index-len-1701072719744="4898" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <style" data-textnode-index-1701072719744="727" data-index-1701072719744="4913" data-index-len-1701072719744="4913" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        ...
        </style" data-textnode-index-1701072719744="732" data-index-1701072719744="4940" data-index-len-1701072719744="4940" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    </template" data-textnode-index-1701072719744="736" data-index-1701072719744="4955" data-index-len-1701072719744="4955" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    <trace-ele name="webComponent" version="0.0.1" desc="原生態自帶隔離的組件"" data-textnode-index-1701072719744="752" data-index-1701072719744="5024" data-index-len-1701072719744="5024" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
        <div slot="slot-ele"" data-textnode-index-1701072719744="760" data-index-1701072719744="5053" data-index-len-1701072719744="5053" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>插槽內容</div" data-textnode-index-1701072719744="764" data-index-1701072719744="5063" data-index-len-1701072719744="5063" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
    </trace-ele" data-textnode-index-1701072719744="768" data-index-1701072719744="5079" data-index-len-1701072719744="5079" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
</body" data-textnode-index-1701072719744="771" data-index-1701072719744="5086" data-index-len-1701072719744="5086" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>

這樣我們就可以實現自定義插槽內容了。

事件綁定

Web Component也可以給組件中元素或者插槽綁定事件。

class Trace extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({ mode: "open" });

    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);
    cloneEle
      .querySelector(".container " data-textnode-index-1701072719744="812" data-index-1701072719744="5401" data-index-len-1701072719744="5401" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> .title")
      .addEventListener("click", this.onClick);

    this.shadowRoot.appendChild(cloneEle);
  }

  onClick = () =" data-textnode-index-1701072719744="825" data-index-1701072719744="5519" data-index-len-1701072719744="5519" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> {
    alert("Click Me!");
  };
}

customElements.define("trace-ele", Trace);

圖片圖片

總結

上面主要給大家分享了一下 Web Component 的一些使用方法。總的來說,Web Component 是一系列 API 的組合:

  • Custom Element:注冊和使用組件
  • Shadow DOM:隔離 CSS
  • HTML template 和 slot:靈活的 DOM 結構

它看起來仿佛是現在主流框架的基建實現,框架也正是基于原生的能力實現出一整套的解決方案,就比如Vue的響應式以來追蹤、模板語法數據綁定,都是我們希望看到的。

責任編輯:武曉燕 來源: 量子前端
相關推薦

2023-12-22 19:59:15

2021-08-04 16:06:45

DataOps智領云

2023-05-20 17:58:31

低代碼軟件

2022-10-20 08:01:23

2021-12-29 18:00:19

無損網絡網絡通信網絡

2022-12-01 17:23:45

2022-07-05 06:30:54

云網絡網絡云原生

2025-10-14 09:01:20

2022-07-26 00:00:03

語言模型人工智能

2022-11-06 21:14:02

數據驅動架構數據

2018-09-28 14:06:25

前端緩存后端

2025-04-03 10:56:47

2022-09-22 09:00:46

CSS單位

2023-08-01 19:11:05

瀏覽器本地存儲

2022-09-27 13:34:49

splice零拷貝原理

2019-04-24 12:30:36

2021-12-16 14:45:09

https架構服務端

2022-09-21 09:04:07

Python裝飾器

2025-01-24 14:38:51

2021-09-04 19:04:14

配置LogbackJava
點贊
收藏

51CTO技術棧公眾號

老汉av免费一区二区三区| 国产成人影院| 天堂av电影在线观看| 99亚洲伊人久久精品影院红桃| 一区二区三欧美| 成人51免费| 久久人人爽人人爽人人av| 黄页视频在线播放| 国产免费av国片精品草莓男男 | 日韩专区欧美专区| 国产成人激情av| 亚洲一区免费观看| 毛片免费在线| 麻豆一区二区在线| 美女福利视频在线| 亚洲男人的天堂av| 午夜视频久久久| 综合色就爱涩涩涩综合婷婷| 免费91麻豆精品国产自产在线观看| 欧美久久精品| 国产日产亚洲精品系列| 国产福利在线免费| 丁香天五香天堂综合| 国产精品久久久久久久乖乖| 国产成人在线视频免费播放| 黄色一级二级三级| 亚洲视频在线免费看| 欧美日韩国产在线看| 国产日韩在线观看视频| 欧美酷刑日本凌虐凌虐| 国产传媒在线视频| 精品国产一区二区三区| 亚洲一区免费视频| 日日碰狠狠丁香久燥| 国产精品2024| 中文字幕欧美人与畜| 亚洲中字在线| 亚洲一二在线观看| 粗暴91大变态调教| 精品一级视频| 亚洲一区二区在线播放相泽| 久久久久国产精品熟女影院 | 亚洲欧美自拍偷拍色图| 国产精品扒开腿爽爽爽视频| 国模大尺度视频一区二区| 亚洲跨种族黑人xxx| 在线观看的黄色| 亚洲欧美国产精品| 123成人网| 欧美成人午夜视频| 哺乳挤奶一区二区三区免费看| 久久99热精品| 免费成人结看片| 国产在线视频91| 欧美日本精品| 亚洲天堂色网站| 深夜成人福利| 一区二区高清在线| 亚洲欧美影院| 国产99精品国产| 国产一区亚洲二区三区| 91免费视频网址| 最近中文字幕2019第二页视频| 一区二区三区视频在线观看| 外国精品视频在线观看| 欧美一区二区在线免费观看| 免费毛片b在线观看| 深夜成人在线观看| 在线观影网站| 91精品久久久久久久99蜜桃| 超碰网在线观看| 国产精品乱人伦中文| 老鸭窝av在线| 麻豆精品一区二区三区| 日韩久久久久久久久久久久| 久久久久久久电影| 在线观看av片| 日韩av一区在线观看| 4kfree性满足欧美hd18| 亚洲一区在线免费观看| 国产午夜在线视频| 亚洲丝袜制服诱惑| 诱人的瑜伽老师3hd中字| 欧美日韩亚洲国产一区| 黑人精品视频| 久久免费视频在线观看| 中文字幕一区二区三区在线视频 | 久久精品人人做人人综合| 在线看片你懂得| 亚洲激情第一页| 欧美一区二区三区红桃小说| 国产日韩精品一区观看| 国产成人调教视频在线观看| 国产视频99| 久久看人人爽人人| 91大神在线网站| 欧美另类高清videos| 欧美日韩综合| 午夜免费福利小电影| 日本亚洲欧美天堂免费| 成年人视频在线免费| 欧美三级在线播放| 国产福利91精品一区二区| 91精品视频大全| 成人av手机在线观看| 免费在线观看污视频| 视频在线观看一区二区| 亚洲国产二区| 国产乱xxⅹxx国语对白| 日韩精品最新网址| 免费在线视频你懂得| 亚洲欧美综合图区| 欧美日本一区二区视频在线观看 | 亚洲高清av在线| 精品久久久久久久久久久aⅴ| 国产一区二区三区播放| 色婷婷狠狠综合| 香蕉加勒比综合久久| 91制片厂免费观看| 亚洲男人的天堂av| 亚洲精品一区三区三区在线观看| 97伦理在线四区| 亚洲人成网站影音先锋播放| 成人亚洲欧美| 久久亚洲精品欧美| 亚洲电影一区二区三区| 国产不卡视频| 亚洲视频一二三| 日本不卡1234视频| 国产精品一级久久久| 亚洲美女淫视频| 麻豆精品国产| 特大黑人娇小亚洲女mp4| 欧美久久久影院| 99精品美女| www.一区二区三区| 国产精品国产三级国产普通话蜜臀| 韩日精品一区| 中文字幕一区二区三区四区五区| 日本道精品一区二区三区| 日韩在线麻豆| 成人一级片网站| 最近2019年手机中文字幕| 日韩影院在线观看| 成人看片免费| 久久香蕉综合色| 欧美性感一区二区三区| 丁香花在线高清完整版视频| yellow视频在线观看一区二区| 亚洲大片在线观看| 九九热精品视频在线观看| 2025韩国理伦片在线观看| 夜夜揉揉日日人人青青一国产精品| 中文一区一区三区高中清不卡免费 | 国产午夜精品理论片a级大结局| 成年美女黄网站色大片不卡| 亚洲精品自在在线观看| 日韩一二三区视频| 性欧美videos另类喷潮| 日韩在线免费电影| 亚洲精品视频在线观看视频| 激情亚洲小说| 国产精品嫩草影院一区二区 | 丁香五月网久久综合| 欧美午夜宅男影院在线观看| 日韩中字在线| 青青草超碰在线| 亚洲福利视频免费观看| 日本在线不卡视频一二三区| 精品美女在线观看视频在线观看| 精品国产乱码久久久久久88av| 国产美女精品人人做人人爽 | 亚洲精品乱码久久久久久蜜桃91| 日韩精品中文字幕在线一区| 久久精品国产99久久6| 成人免费影院| 亚洲成熟丰满熟妇高潮xxxxx| 韩国精品久久久999| 亚洲永久精品国产| 欧美黄色一区| 伊人影院在线视频| 日本大片免费看| 欧美高清视频一区二区| 国内少妇毛片视频| 在线观看久久久久久| www国产成人免费观看视频 深夜成人网| 日本在线成人| 国产成人成网站在线播放青青| 91久久精品一区二区三| 亚洲一区一卡| 日韩电影免费看| 免费男同深夜夜行网站 | 精品一区二区三区不卡 | 日韩久久久精品| 成人少妇影院yyyy| 欧美激情久久久久久久久久久| 精品资源在线看| 日本女人高潮视频| 97**国产露脸精品国产| 国产精品一卡二卡在线观看|