最新WebComponent开发教程

Admin 2023-04-01 群英技术资讯 384 次浏览

这篇文章主要介绍“最新WebComponent开发教程”的相关知识,下面会通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“最新WebComponent开发教程”文章能帮助大家解决问题。


目录
  • 正文
  • 三项主要技术
    • 1、Custom elements (自定义元素)
      • 生命周期函数
    • 2、HTML templates(HTML 模板)
      • 3、Shadow DOM(影子 DOM)
      • 动态创建 webComponent 组件例子

        正文

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

        一个简单例子,让页面显示 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 及其行为,然后可以在您的用户界面中按照需要使用它们

        分为两种形式:

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

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

        • 使用时需通过 is 属性指定 custom element 的名称,必须包含一个短横线
        • 注册的时候必须使用 extends 的属性
        <!-- 自定义内置元素 使用 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 生命周期函数,处理节点操作

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

        生命周期函数

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

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

        adoptedCallback:被移动新文档时

        attributeChangedCallback:属性变化时

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

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

        例子:

        <body>
          <div id="container">
            <p is="my-text" text="云牧" id="myText"></p>
          </div>
          <button id="btnUpdateText">更新属性</button>
          <button id="btnRemove">删除节点</button>
          <button id="btnRestore">恢复节点</button>
          <button id="btnAdopt">移动节点</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 = "";
              }
              // 监测的属性
              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));
            });
          </script>
        </body>
        

        2、HTML templates(HTML 模板)

        • 使用 JS 模板字串符的方式创建模板,提示不友好,复用性差
        <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);
                // 插入克隆的模板内容
                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">默认内容</slot>
          </template>
          <test-item>
            <div slot="slot-des">不是默认内容</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)

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

        <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,其内部元素不可以直接被访问到

        有一个重要的参数 mode

        • open: shadow root 元素通过 js 从外部访问根节点
        • closed:拒绝 js 从外部访问关闭的 shadow root 节点
        <body>
          <template id="tpl">
            <div class="title"></div>
            <div class="des"></div>
          </template>
          <note-item class="note-item" title="标题" des="内容"></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 则可以继续访问操作内部 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>
        

        动态创建 webComponent 组件例子

        • 通过创建 商品 组件,并使得点击能跳转
        <body>
          <div id="product-list" style="display: flex"></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 => {
              // 创建组件
              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>

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

        您可能感兴趣的文章:
        • vue+webpack 更换主题N种方案优劣分析
        • webpack5新特性Asset Modules资源模块详解
        • WebAssembly增强前端应用技巧详解
        • electron 中 webview的使用示例解析
        • js 交互在Flutter 中使用 webview_flutter
        • 详解web如何改变主题配色方法示例

        “最新WebComponent开发教程”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业技术相关的知识可以关注群英网络网站,小编每天都会为大家更新不同的知识。 群英智防CDN,智能加速解决方案

        免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

        猜你喜欢

        成为群英会员,开启智能安全云计算之旅

        立即注册
        专业资深工程师驻守
        7X24小时快速响应
        一站式无忧技术支持
        免费备案服务
        免费拨打  400-678-4567
        免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
        在线客服
        微信公众号
        返回顶部
        返回顶部 返回顶部
        在线客服
        在线客服