广告位联系
返回顶部
分享到

WebComponent使用教程介绍

JavaScript 来源:互联网 作者:佚名 发布时间:2023-10-30 22:41:58 人浏览
摘要

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

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

<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 的属性

1

2

3

4

5

6

7

8

9

10

11

12

13

14

<!-- 自定义内置元素 使用 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 生命周期函数,处理节点操作

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<!-- 自主定制元素-->

<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 方法更新属性

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

例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

<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 模板字串符的方式创建模板,提示不友好,复用性差

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<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 方式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

<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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

<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,其内部样式不共享

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

<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 节点

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

<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>

引入外部样式:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<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 组件例子

  • 通过创建 商品 组件,并使得点击能跳转

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

<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>


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。

您可能感兴趣的文章 :

原文链接 :
    Tag :
相关文章
  • 不可变数据方案之immer.js原理介绍

    不可变数据方案之immer.js原理介绍
    本篇文章是JavaScript 函数式编程 学习系列第三篇 前一篇JavaScript数据类型对函数式编程的影响讲到了不可变数据的重要性,而让数据不可变的
  • WebComponent使用教程介绍

    WebComponent使用教程介绍
    WebComponent 是官方定义的自定义组件实现方式,它可以让开发者不依赖任何第三方框架(如Vue,React)来实现自定义页面组件;达到组件复用
  • element plus的样式修改和扩展实例介绍
    一、用户故事 我们开发了一个业务组件库。业务组件库是需要基于公司内部的一个UI组件库。而公司的UI组件库又出基于element ui的。 公司的
  • element弹窗表格的字体模糊bug解决方法

    element弹窗表格的字体模糊bug解决方法
    有一个BUG,就是在使用element弹窗表格的字体异常的模糊。如下图: 这个问题其实已经存在很久了。客户屡有反馈,但是不多。我们基本自测
  • 如何在JavaScript中使用媒体查询介绍

    如何在JavaScript中使用媒体查询介绍
    说起媒体查询想必大家最先想到的都是CSS中@media,没错,这是我们最常用的媒体查询方法,主要用来为我们的网站做适配处理。 比如: 1
  • js二进制数据及其互相转化的实现
    file 在js中有很多二进制数据,有file,base64,Blob,ArrayBuffer,FileReader。这些二进制数据在文件导出和下载的时候是经常会用到的,我们这篇文章就
  • JS实现简单的操作杆旋转示例介绍

    JS实现简单的操作杆旋转示例介绍
    JS 简单的操作杆旋转实现 首先说明一下,请直接忽略背景图,这里主要实现的是杆旋转控制方向盘旋转。 鼠标移出控制区域,控制球复位
  • smartbanner.js实现可定制智能应用横幅使用示例
    smartbanner.js 适用于 iOS 和 Android 的可定制智能应用横幅(smart app banner)。简单易用,不依赖任何框架,怎么使用官方文档也写的很清楚,我就不
  • js的一些潜在规则使用介绍

    js的一些潜在规则使用介绍
    为什么开发中建议使用void 0 来代替undefined 因为 JavaScript 的代码 undefined 是一个变量,而并非是一个关键字,这是JavaScript 语言公认的设计失
  • 基于JavaScript实现图片滤镜效果介绍
    随着社交媒体的普及,人们对于图片的处理需求越来越高。图片滤镜效果成为了许多人喜爱的功能之一。在本文中,我们将学习如何使用
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计