翼度科技»论坛 编程开发 JavaScript 查看内容

2023年了该了解下WebComponent使用教程

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
正文

WebComponent 是官方定义的自定义组件实现方式,它可以让开发者不依赖任何第三方框架(如Vue,React)来实现自定义页面组件;达到组件复用效果
一个简单例子,让页面显示 hello world:
  1. <body>
  2.   <!-- 使用组件的方式 -->
  3.   <my-text />
  4.   <script>
  5.     class MyText extends HTMLElement {
  6.       constructor() {
  7.         super();
  8.         this.append("hello world");
  9.       }
  10.     }
  11.     window.customElements.define("my-text", MyText);
  12.   </script>
  13. </body>
复制代码
三项主要技术


1、Custom elements (自定义元素)


  • 一组 JavaScript API,允许您定义 custom elements 及其行为,然后可以在您的用户界面中按照需要使用它们
分为两种形式:
自主定制元素:是独立的元素,它不继承其他内建的 HTML 元素,可以直接把它们写成 HTML 标签的形式,来在页面上使用,例如我们刚才自定义的
  1. <my-text>
复制代码
自定义内置元素:继承自内置的 HTML 元素。指定所需扩展的元素

  • 使用时需通过
    1. is
    复制代码
    属性指定
    1. custom element
    复制代码
    的名称,必须包含一个短横线
  • 注册的时候必须使用
    1. extends
    复制代码
    的属性
  1. <!-- 自定义内置元素 使用 is-->
  2. <body>
  3.   <!-- 使用组件的方式 -->
  4.   <p is="color-p" color="green">云牧</p>
  5.   <script>
  6.     class ColorP extends HTMLParagraphElement {
  7.       constructor() {
  8.         super();
  9.         this.style.color = this.getAttribute("color");
  10.       }
  11.     }
  12.     window.customElements.define("color-p", ColorP, { extends: "p" });
  13.   </script>
  14. </body>
复制代码
推荐在
  1. connectedCallback
复制代码
生命周期函数,处理节点操作
  1. <!-- 自主定制元素-->
  2. <body>
  3.   <my-text />
  4.   <script>
  5.     class MyText extends HTMLElement {
  6.       constructor() {
  7.         super();
  8.       }
  9.       connectedCallback() {
  10.         this.append("hello world");
  11.       }
  12.     }
  13.     window.customElements.define("my-text", MyText);
  14.   </script>
  15. </body>
复制代码
生命周期函数
  1. connectedCallback
复制代码
:插入文档时,可能被多次触发,比如删除后又添加到文档
  1. disconnectedCallback
复制代码
:从文档删除时,可配置做清理工作
  1. adoptedCallback
复制代码
:被移动新文档时
  1. attributeChangedCallback
复制代码
:属性变化时

  • 配合
    1. observedAttributess
    复制代码
    属性一起使用,指定监听的属性
  • 使用
    1. setAttribute
    复制代码
    方法更新属性
不同操作触发的生命周期函数:

例子:
  1. <body>
  2.   <div id="container">
  3.     <p is="my-text" text="云牧" id="myText"></p>
  4.   </div>
  5.   <button id="btnUpdateText">更新属性</button>
  6.   <button id="btnRemove">删除节点</button>
  7.   <button id="btnRestore">恢复节点</button>
  8.   <button id="btnAdopt">移动节点</button>
  9.   <iframe src="./ifr.html" id="ifr"></iframe>
  10.   <script>
  11.     class MyText extends HTMLParagraphElement {
  12.       constructor() {
  13.         super();
  14.       }
  15.       connectedCallback() {
  16.         console.log("生命周期:connectedCallback");
  17.         this.append("你好:" + this.getAttribute("text"));
  18.       }
  19.       disconnectedCallback() {
  20.         console.log("生命周期:disconnectedCallback");
  21.         this.innerHTML = "";
  22.       }
  23.       // 监测的属性
  24.       static get observedAttributes() {
  25.         return ["text"];
  26.       }
  27.       attributeChangedCallback(name, oldValue, newValue) {
  28.         console.log("生命周期:attributeChangedCallback", name, oldValue, newValue);
  29.         // 最先触发是此函数,判断是不是第一次触发,第一次的话,只由 connectedCallback 处理
  30.         if (oldValue != null) {
  31.           this.replaceChildren("你好:" + newValue);
  32.         }
  33.       }
  34.       adoptedCallback() {
  35.         console.log("生命周期:adoptedCallback");
  36.       }
  37.     }
  38.     window.customElements.define("my-text", MyText, { extends: "p" });
  39.     const myText = document.getElementById("myText");
  40.     btnUpdateText.addEventListener("click", function (e) {
  41.       myText.setAttribute("text", "黛玉");
  42.     });
  43.     btnRemove.addEventListener("click", function (e) {
  44.       myText.remove();
  45.     });
  46.     btnRestore.addEventListener("click", function (e) {
  47.       container.appendChild(myText);
  48.     });
  49.     btnAdopt.addEventListener("click", () => {
  50.       const textNode = ifr.contentWindow.document.getElementById("myText");
  51.       container.appendChild(document.adoptNode(textNode));
  52.     });
  53.   </script>
  54. </body>
复制代码
2、HTML templates(HTML 模板)


  • 使用 JS 模板字串符的方式创建模板,提示不友好,复用性差
  1. <body>
  2.   <product-item
  3.     name="关东煮"
  4.     img="//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp"
  5.     price="49.8"
  6.   ></product-item>
  7.   <script>
  8.     class ProductItem extends HTMLElement {
  9.       constructor() {
  10.         super();
  11.       }
  12.       connectedCallback() {
  13.         const content = `
  14.                   <img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
  15.                   <div class="name"></div>
  16.                   <div class="price"></div>
  17.               `;
  18.         this.innerHTML = content;
  19.         this.querySelector(".img").src = this.getAttribute("img");
  20.         this.querySelector(".name").innerText = this.getAttribute("name");
  21.         this.querySelector(".price").innerText = this.getAttribute("price");
  22.       }
  23.     }
  24.     window.customElements.define("product-item", ProductItem);
  25.   </script>
  26. </body>
复制代码
template 方式
  1. <body>
  2.   <!-- template -->
  3.   <template id="tpl-product-item">
  4.     <img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
  5.     <div class="name"></div>
  6.     <div class="price"></div>
  7.   </template>
  8.   <product-item
  9.     name="关东煮"
  10.     img="//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp"
  11.     price="49.8"
  12.   ></product-item>
  13.   <script>
  14.     class ProductItem extends HTMLElement {
  15.       constructor() {
  16.         super();
  17.       }
  18.       connectedCallback() {
  19.         const content = document.getElementById("tpl-product-item").content.cloneNode(true);
  20.         // 插入克隆的模板内容
  21.         this.append(content);
  22.         this.querySelector(".img").src = this.getAttribute("img");
  23.         this.querySelector(".name").innerText = this.getAttribute("name");
  24.         this.querySelector(".price").innerText = this.getAttribute("price");
  25.       }
  26.     }
  27.     window.customElements.define("product-item", ProductItem);
  28.   </script>
  29. </body>
复制代码
slot
  1. <body>
  2.   <template id="tpl-test">
  3.     <style>
  4.       .title {
  5.         color: green;
  6.       }
  7.     </style>
  8.     <div class="title">标题</div>
  9.     <slot name="slot-des">默认内容</slot>
  10.   </template>
  11.   <test-item>
  12.     <div slot="slot-des">不是默认内容</div>
  13.   </test-item>
  14.   <script>
  15.     class TestItem extends HTMLElement {
  16.       constructor() {
  17.         super();
  18.       }
  19.       connectedCallback() {
  20.         const content = document.getElementById("tpl-test").content.cloneNode(true);
  21.         const shadow = this.attachShadow({ mode: "open" });
  22.         shadow.append(content);
  23.       }
  24.     }
  25.     window.customElements.define("test-item", TestItem);
  26.   </script>
  27. </body>
复制代码
3、Shadow DOM(影子 DOM)


影子DOM,其内部样式不共享
  1. <body>
  2.   <!--  不受外部 .container.container 的颜色影响 -->
  3.   <my-item-s></my-item-s>
  4.   <div class="container">My item</div>
  5.   <style>
  6.     .container.container {
  7.       color: green;
  8.     }
  9.   </style>
  10.   <template id="tpl">
  11.     <style>
  12.       .container {
  13.         color: pink;
  14.       }
  15.     </style>
  16.     <div class="container">My Item</div>
  17.   </template>
  18.   <script>
  19.     class MyItemShadow extends HTMLElement {
  20.       constructor() {
  21.         super();
  22.       }
  23.       connectedCallback() {
  24.         const content = document.getElementById("tpl").content.cloneNode(true);
  25.         const shadow = this.attachShadow({ mode: "open" });
  26.         shadow.append(content);
  27.       }
  28.     }
  29.     window.customElements.define("my-item-s", MyItemShadow);
  30.   </script>
  31. </body>
复制代码
影子DOM,其内部元素不可以直接被访问到
有一个重要的参数 mode

  • open: shadow root 元素通过 js 从外部访问根节点
  • closed:拒绝 js 从外部访问关闭的 shadow root 节点
  1. <body>
  2.   <template id="tpl">
  3.     <div class="title"></div>
  4.     <div class="des"></div>
  5.   </template>
  6.   <note-item class="note-item" title="标题" des="内容"></note-item>
  7.   <script>
  8.     class NoteItem extends HTMLElement {
  9.       constructor() {
  10.         super();
  11.       }
  12.       connectedCallback() {
  13.         const content = document.getElementById("tpl").content.cloneNode(true);
  14.         const shadow = this.attachShadow({ mode: "open" });
  15.         shadow.append(content);
  16.         // 如果是 open 则可以继续访问操作内部 dom
  17.         // console.log(document.querySelector(".note-item").shadowRoot.querySelector(".title"));
  18.         shadow.querySelector(".title").textContent = this.getAttribute("title");
  19.         shadow.querySelector(".des").textContent = this.getAttribute("des");
  20.       }
  21.     }
  22.     window.customElements.define("note-item", NoteItem);
  23.   </script>
  24. </body>
复制代码
引入外部样式:
  1. <body>
  2.   <template id="tpl">
  3.     <!-- 方式一: -->
  4.     <link rel="stylesheet" href="index.css" rel="external nofollow"  />
  5.     <div>My Item</div>
  6.   </template>
  7.   <my-item></my-item>
  8.   <script>
  9.     class MyItem extends HTMLElement {
  10.       constructor() {
  11.         super();
  12.       }
  13.       connectedCallback() {
  14.         const content = document.getElementById("tpl").content.cloneNode(true);
  15.         const shadow = this.attachShadow({ mode: "open" });
  16.         shadow.append(content);
  17.         // 方式二:
  18.         const linkEl = document.createElement("link");
  19.         linkEl.setAttribute("rel", "stylesheet");
  20.         linkEl.setAttribute("href", "index.css");
  21.         shadow.appendChild(linkEl);
  22.       }
  23.     }
  24.     window.customElements.define("my-item", MyItem);
  25.   </script>
  26. </body>
复制代码
动态创建 webComponent 组件例子


  • 通过创建 商品 组件,并使得点击能跳转
  1. <body>
  2.   <div id="product-list" style="display: flex"></div>
  3.   <template id="product-item">
  4.     <style>
  5.       .product-item {
  6.         margin-left: 15px;
  7.         cursor: pointer;
  8.       }
  9.       .img {
  10.         width: 100px;
  11.       }
  12.       .name {
  13.         text-align: center;
  14.       }
  15.       .price {
  16.         color: #999;
  17.         text-align: center;
  18.       }
  19.     </style>
  20.     <div class="product-item">
  21.       <img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
  22.       <div class="name"></div>
  23.       <div class="price"></div>
  24.     </div>
  25.   </template>
  26.   <script>
  27.     class ProductItemElement extends HTMLElement {
  28.       constructor(props) {
  29.         super(props);
  30.         this.addEventListener("click", () => {
  31.           window.open(`https://item.jd.com/${this.id}.html`);
  32.         });
  33.       }
  34.       connectedCallback() {
  35.         const shadow = this.attachShadow({ mode: "open" });
  36.         const content = document.getElementById("product-item").content.cloneNode(true);
  37.         content.querySelector(".img").src = this.img;
  38.         content.querySelector(".name").innerText = this.name;
  39.         content.querySelector(".price").innerText = this.price;
  40.         shadow.appendChild(content);
  41.       }
  42.     }
  43.     window.customElements.define("product-item", ProductItemElement);
  44.   </script>
  45.   <script>
  46.     const products = [
  47.       {
  48.         name: "关东煮",
  49.         img: "//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp",
  50.         id: "10026249568453",
  51.         price: 49.8
  52.       },
  53.       {
  54.         name: "土鸡蛋",
  55.         img: "//img11.360buyimg.com/seckillcms/s200x200_jfs/t1/172777/32/27438/130981/61fbd2e0E236000e0/7f5284367e2f5da6.jpg!cc_200x200.webp",
  56.         id: "10024773802639",
  57.         price: 49.8
  58.       },
  59.       {
  60.         name: "东北蜜枣粽子",
  61.         img: "//img20.360buyimg.com/seckillcms/s200x200_jfs/t1/129546/31/19459/110768/60b1f4b4Efd47366c/3a5b80c5193bc6ce.jpg!cc_200x200.webp",
  62.         id: "10035808728318",
  63.         price: 15
  64.       }
  65.     ];
  66.     const productList = document.getElementById("product-list");
  67.     const elList = products.map(product => {
  68.       // 创建组件
  69.       const el = document.createElement("product-item");
  70.       el.img = product.img;
  71.       el.name = product.name;
  72.       el.price = product.price;
  73.       el.id = product.id;
  74.       return el;
  75.     });
  76.     productList.append.apply(productList, elList);
  77.   </script>
  78. </body>
复制代码
以上就是2023年了该了解下WebComponent使用教程的详细内容,更多关于WebComponent使用教程的资料请关注脚本之家其它相关文章!

来源:https://www.jb51.net/article/276362.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具