溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

WebComponent如何使用

發(fā)布時間:2023-02-24 13:57:11 來源:億速云 閱讀:170 作者:iii 欄目:開發(fā)技術

本篇內(nèi)容介紹了“WebComponent如何使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

    正文

    WebComponent 是官方定義的自定義組件實現(xiàn)方式,它可以讓開發(fā)者不依賴任何第三方框架(如Vue,React)來實現(xiàn)自定義頁面組件;達到組件復用效果

    一個簡單例子,讓頁面顯示 hello world:

    <body>
      <!-- 使用組件的方式 -->
      <my-text />
      <script>
        class MyText extends HTMLElement {
          constructor() {
            super();
            this.append("hello world");
          }
        }
        window.customElements.define("my-text", MyText);
      </script>
    </body>

    三項主要技術

    1、Custom elements (自定義元素)

    • 一組 JavaScript API,允許您定義 custom elements 及其行為,然后可以在您的用戶界面中按照需要使用它們

    分為兩種形式:

    自主定制元素:是獨立的元素,它不繼承其他內(nèi)建的 HTML 元素,可以直接把它們寫成 HTML 標簽的形式,來在頁面上使用,例如我們剛才自定義的 <my-text>

    自定義內(nèi)置元素:繼承自內(nèi)置的 HTML 元素。指定所需擴展的元素

    • 使用時需通過 is 屬性指定 custom element 的名稱,必須包含一個短橫線

    • 注冊的時候必須使用 extends 的屬性

    <!-- 自定義內(nèi)置元素 使用 is-->
    <body>
      <!-- 使用組件的方式 -->
      <p is="color-p" color="green">云牧</p>
      <script>
        class ColorP extends HTMLParagraphElement {
          constructor() {
            super();
            this.style.color = this.getAttribute("color");
          }
        }
        window.customElements.define("color-p", ColorP, { extends: "p" });
      </script>
    </body>

    推薦在 connectedCallback 生命周期函數(shù),處理節(jié)點操作

    <!-- 自主定制元素-->
    <body>
      <my-text />
      <script>
        class MyText extends HTMLElement {
          constructor() {
            super();
          }
          connectedCallback() {
            this.append("hello world");
          }
        }
        window.customElements.define("my-text", MyText);
      </script>
    </body>

    生命周期函數(shù)

    connectedCallback:插入文檔時,可能被多次觸發(fā),比如刪除后又添加到文檔

    disconnectedCallback:從文檔刪除時,可配置做清理工作

    adoptedCallback:被移動新文檔時

    attributeChangedCallback:屬性變化時

    • 配合 observedAttributess 屬性一起使用,指定監(jiān)聽的屬性

    • 使用 setAttribute 方法更新屬性

    不同操作觸發(fā)的生命周期函數(shù):

    WebComponent如何使用

    例子:

    <body>
      <div id="container">
        <p is="my-text" text="云牧" id="myText"></p>
      </div>
      <button id="btnUpdateText">更新屬性</button>
      <button id="btnRemove">刪除節(jié)點</button>
      <button id="btnRestore">恢復節(jié)點</button>
      <button id="btnAdopt">移動節(jié)點</button>
      <iframe src="./ifr.html" id="ifr"></iframe>
      <script>
        class MyText extends HTMLParagraphElement {
          constructor() {
            super();
          }
          connectedCallback() {
            console.log("生命周期:connectedCallback");
            this.append("你好:" + this.getAttribute("text"));
          }
          disconnectedCallback() {
            console.log("生命周期:disconnectedCallback");
            this.innerHTML = "";
          }
          // 監(jiān)測的屬性
          static get observedAttributes() {
            return ["text"];
          }
          attributeChangedCallback(name, oldValue, newValue) {
            console.log("生命周期:attributeChangedCallback", name, oldValue, newValue);
            // 最先觸發(fā)是此函數(shù),判斷是不是第一次觸發(fā),第一次的話,只由 connectedCallback 處理
            if (oldValue != null) {
              this.replaceChildren("你好:" + newValue);
            }
          }
          adoptedCallback() {
            console.log("生命周期:adoptedCallback");
          }
        }
        window.customElements.define("my-text", MyText, { extends: "p" });
        const myText = document.getElementById("myText");
        btnUpdateText.addEventListener("click", function (e) {
          myText.setAttribute("text", "黛玉");
        });
        btnRemove.addEventListener("click", function (e) {
          myText.remove();
        });
        btnRestore.addEventListener("click", function (e) {
          container.appendChild(myText);
        });
        btnAdopt.addEventListener("click", () => {
          const textNode = ifr.contentWindow.document.getElementById("myText");
          container.appendChild(document.adoptNode(textNode));
        });
      </script>
    </body>

    2、HTML templates(HTML 模板)

    • 使用 JS 模板字串符的方式創(chuàng)建模板,提示不友好,復用性差

    <body>
      <product-item
        name="關東煮"
        img="//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp"
        price="49.8"
      ></product-item>
      <script>
        class ProductItem extends HTMLElement {
          constructor() {
            super();
          }
          connectedCallback() {
            const content = `
                      <img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
                      <div class="name"></div>
                      <div class="price"></div>
                  `;
            this.innerHTML = content;
            this.querySelector(".img").src = this.getAttribute("img");
            this.querySelector(".name").innerText = this.getAttribute("name");
            this.querySelector(".price").innerText = this.getAttribute("price");
          }
        }
        window.customElements.define("product-item", ProductItem);
      </script>
    </body>

    template 方式

    <body>
      <!-- template -->
      <template id="tpl-product-item">
        <img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
        <div class="name"></div>
        <div class="price"></div>
      </template>
      <product-item
        name="關東煮"
        img="//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp"
        price="49.8"
      ></product-item>
      <script>
        class ProductItem extends HTMLElement {
          constructor() {
            super();
          }
          connectedCallback() {
            const content = document.getElementById("tpl-product-item").content.cloneNode(true);
            // 插入克隆的模板內(nèi)容
            this.append(content);
            this.querySelector(".img").src = this.getAttribute("img");
            this.querySelector(".name").innerText = this.getAttribute("name");
            this.querySelector(".price").innerText = this.getAttribute("price");
          }
        }
        window.customElements.define("product-item", ProductItem);
      </script>
    </body>

    slot

    <body>
      <template id="tpl-test">
        <style>
          .title {
            color: green;
          }
        </style>
        <div class="title">標題</div>
        <slot name="slot-des">默認內(nèi)容</slot>
      </template>
      <test-item>
        <div slot="slot-des">不是默認內(nèi)容</div>
      </test-item>
      <script>
        class TestItem extends HTMLElement {
          constructor() {
            super();
          }
          connectedCallback() {
            const content = document.getElementById("tpl-test").content.cloneNode(true);
            const shadow = this.attachShadow({ mode: "open" });
            shadow.append(content);
          }
        }
        window.customElements.define("test-item", TestItem);
      </script>
    </body>

    3、Shadow DOM(影子 DOM)

    WebComponent如何使用

    影子DOM,其內(nèi)部樣式不共享

    <body>
      <!--  不受外部 .container.container 的顏色影響 -->
      <my-item-s></my-item-s>
      <div class="container">My item</div>
      <style>
        .container.container {
          color: green;
        }
      </style>
      <template id="tpl">
        <style>
          .container {
            color: pink;
          }
        </style>
        <div class="container">My Item</div>
      </template>
      <script>
        class MyItemShadow extends HTMLElement {
          constructor() {
            super();
          }
          connectedCallback() {
            const content = document.getElementById("tpl").content.cloneNode(true);
            const shadow = this.attachShadow({ mode: "open" });
            shadow.append(content);
          }
        }
        window.customElements.define("my-item-s", MyItemShadow);
      </script>
    </body>

    影子DOM,其內(nèi)部元素不可以直接被訪問到

    有一個重要的參數(shù) mode

    • open: shadow root 元素通過 js 從外部訪問根節(jié)點

    • closed:拒絕 js 從外部訪問關閉的 shadow root 節(jié)點

    <body>
      <template id="tpl">
        <div class="title"></div>
        <div class="des"></div>
      </template>
      <note-item class="note-item" title="標題" des="內(nèi)容"></note-item>
      <script>
        class NoteItem extends HTMLElement {
          constructor() {
            super();
          }
          connectedCallback() {
            const content = document.getElementById("tpl").content.cloneNode(true);
            const shadow = this.attachShadow({ mode: "open" });
            shadow.append(content);
            // 如果是 open 則可以繼續(xù)訪問操作內(nèi)部 dom
            // console.log(document.querySelector(".note-item").shadowRoot.querySelector(".title"));
            shadow.querySelector(".title").textContent = this.getAttribute("title");
            shadow.querySelector(".des").textContent = this.getAttribute("des");
          }
        }
        window.customElements.define("note-item", NoteItem);
      </script>
    </body>

    引入外部樣式:

    <body>
      <template id="tpl">
        <!-- 方式一: -->
        <link rel="stylesheet" href="index.css" rel="external nofollow"  />
        <div>My Item</div>
      </template>
      <my-item></my-item>
      <script>
        class MyItem extends HTMLElement {
          constructor() {
            super();
          }
          connectedCallback() {
            const content = document.getElementById("tpl").content.cloneNode(true);
            const shadow = this.attachShadow({ mode: "open" });
            shadow.append(content);
            // 方式二:
            const linkEl = document.createElement("link");
            linkEl.setAttribute("rel", "stylesheet");
            linkEl.setAttribute("href", "index.css");
            shadow.appendChild(linkEl);
          }
        }
        window.customElements.define("my-item", MyItem);
      </script>
    </body>

    動態(tài)創(chuàng)建 webComponent 組件例子

    • 通過創(chuàng)建 商品 組件,并使得點擊能跳轉(zhuǎn)

    <body>
      <div id="product-list" ></div>
      <template id="product-item">
        <style>
          .product-item {
            margin-left: 15px;
            cursor: pointer;
          }
          .img {
            width: 100px;
          }
          .name {
            text-align: center;
          }
          .price {
            color: #999;
            text-align: center;
          }
        </style>
        <div class="product-item">
          <img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
          <div class="name"></div>
          <div class="price"></div>
        </div>
      </template>
      <script>
        class ProductItemElement extends HTMLElement {
          constructor(props) {
            super(props);
            this.addEventListener("click", () => {
              window.open(`https://item.jd.com/${this.id}.html`);
            });
          }
          connectedCallback() {
            const shadow = this.attachShadow({ mode: "open" });
            const content = document.getElementById("product-item").content.cloneNode(true);
            content.querySelector(".img").src = this.img;
            content.querySelector(".name").innerText = this.name;
            content.querySelector(".price").innerText = this.price;
            shadow.appendChild(content);
          }
        }
        window.customElements.define("product-item", ProductItemElement);
      </script>
      <script>
        const products = [
          {
            name: "關東煮",
            img: "//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp",
            id: "10026249568453",
            price: 49.8
          },
          {
            name: "土雞蛋",
            img: "//img11.360buyimg.com/seckillcms/s200x200_jfs/t1/172777/32/27438/130981/61fbd2e0E236000e0/7f5284367e2f5da6.jpg!cc_200x200.webp",
            id: "10024773802639",
            price: 49.8
          },
          {
            name: "東北蜜棗粽子",
            img: "//img20.360buyimg.com/seckillcms/s200x200_jfs/t1/129546/31/19459/110768/60b1f4b4Efd47366c/3a5b80c5193bc6ce.jpg!cc_200x200.webp",
            id: "10035808728318",
            price: 15
          }
        ];
        const productList = document.getElementById("product-list");
        const elList = products.map(product => {
          // 創(chuàng)建組件
          const el = document.createElement("product-item");
          el.img = product.img;
          el.name = product.name;
          el.price = product.price;
          el.id = product.id;
          return el;
        });
        productList.append.apply(productList, elList);
      </script>
    </body>

    “WebComponent如何使用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI