目录

正文

WebComponent 是官方定义的自定义组件实现方式,它可以让开发者不依赖任何第三方框架(如Vue,React)来实现自定义页面组件;达到组件复用效果

一个简单例子,让页面显示 hello world:

          class MyText extends HTMLElement {      constructor() {        super();        this.append("hello world");      }    }    window.customElements.define("my-text", MyText);  

三项主要技术

1、Custom elements (自定义元素)

  • 一组 JavaScript API,允许您定义 custom elements 及其行为,然后可以在您的用户界面中按照需要使用它们

分为两种形式:

自主定制元素:是独立的元素,它不继承其他内建的 HTML 元素,可以直接把它们写成 HTML 标签的形式,来在页面上使用,例如我们刚才自定义的

自定义内置元素:继承自内置的 HTML 元素。指定所需扩展的元素

  • 使用时需通过 is 属性指定 custom element 的名称,必须包含一个短横线
  • 注册的时候必须使用 extends 的属性
    

云牧

class ColorP extends HTMLParagraphElement { constructor() { super(); this.style.color = this.getAttribute("color"); } } window.customElements.define("color-p", ColorP, { extends: "p" });

推荐在 connectedCallback 生命周期函数,处理节点操作

        class MyText extends HTMLElement {      constructor() {        super();      }      connectedCallback() {        this.append("hello world");      }    }    window.customElements.define("my-text", MyText);  

生命周期函数

connectedCallback:插入文档时,可能被多次触发,比如删除后又添加到文档

disconnectedCallback:从文档删除时,可配置做清理工作

adoptedCallback:被移动新文档时

attributeChangedCallback:属性变化时

  • 配合 observedAttributess 属性一起使用,指定监听的属性
  • 使用 setAttribute 方法更新属性

不同操作触发的生命周期函数:

例子:

      

class MyText extends HTMLParagraphElement { constructor() { super(); } connectedCallback() { console.log("生命周期:connectedCallback"); this.append("你好:" + this.getAttribute("text")); } disconnectedCallback() { console.log("生命周期:disconnectedCallback"); this.innerHTML = ""; } // 监测的属性 static get observedAttributes() { return ["text"]; } attributeChangedCallback(name, oldValue, newValue) { console.log("生命周期:attributeChangedCallback", name, oldValue, newValue); // 最先触发是此函数,判断是不是第一次触发,第一次的话,只由 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)); });

2、HTML templates(HTML 模板)

  • 使用 JS 模板字串符的方式创建模板,提示不友好,复用性差
        class ProductItem extends HTMLElement {      constructor() {        super();      }      connectedCallback() {        const content = `                                                                    `;        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);  

template 方式

                          class ProductItem extends HTMLElement {      constructor() {        super();      }      connectedCallback() {        const content = document.getElementById("tpl-product-item").content.cloneNode(true);        // 插入克隆的模板内容        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);  

slot

            .title {        color: green;      }        标题    默认内容        不是默认内容        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);  

3、Shadow DOM(影子 DOM)

影子DOM,其内部样式不共享

      My item      .container.container {      color: green;    }              .container {        color: pink;      }        My Item        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);  

影子DOM,其内部元素不可以直接被访问到

有一个重要的参数 mode

  • open: shadow root 元素通过 js 从外部访问根节点
  • closed:拒绝 js 从外部访问关闭的 shadow root 节点
                    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 则可以继续访问操作内部 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);  

引入外部样式:

              My Item          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);  

动态创建 webComponent 组件例子

  • 通过创建 商品 组件,并使得点击能跳转
              .product-item {        margin-left: 15px;        cursor: pointer;      }      .img {        width: 100px;      }      .name {        text-align: center;      }      .price {        color: #999;        text-align: center;      }                                      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);        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 => {      // 创建组件      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);  

以上就是2023年了该了解下WebComponent使用教程的详细内容,更多关于WebComponent使用教程的资料请关注脚本之家其它相关文章!