# Web Component 基础

  • 核心概念
  • Web Component 实战
  • 开源库

# 核心概念

  • Custom elements
  • Shadow DOM
  • HTML templates

# Custom elements

源生 js api,可以在页面上定义自己的 html 标签,同时提供了一套生命周期方案,可以理解成一个 react 或 vue 组件,在浏览器中是可以源生支持的,不需要打包编译即可使用。

实战:编写一个 <hello-world></hello-world> 组件。

class HelloWorld extends HTMLElement {
  constructor() {
    // 必须首先调用 super 方法
    super();
    // 元素的功能代码写在这里
    this.addEventListener("click", () => {
      alert("hello");
    });
  }
}
customElements.define("hello-world", HelloWorld);
1
2
3
4
5
6
7
8
9
10
11

# Shadow DOM

Shadow DOM 的一个重要特性是封装——可以将 html 标签结构、css 样式和行为隐藏起来,并从页面上的其他代码中分离开来,这样不同的功能不会混在一起,代码看起来也会更加干净整洁。

实战:给一个 div 元素,绑定一个 shadowDOM,让一个空 div 也能显示出一个 button。

<div id="container"></div>
<script>
  const container = document.getElementById("container");
  const shadow = container.attachShadow({ mode: "open" });

  // 添加一个button
  const button = document.createElement("button");
  button.textContent = "hello";

  // 插入 shadow dom
  shadow.appendChild(button);
</script>
1
2
3
4
5
6
7
8
9
10
11
12

# HTML templates

当您必须在网页上重复使用相同的标记结构时,使用某种模板而不是一遍又一遍地重复相同的结构是有意义的。此元素及其内容不会在 DOM 中呈现,但仍可使用 JavaScript 去引用它。

实战:实现一个基本的 template 应用。

<template id="my-paragraph">
  <p>My paragraph</p>
</template>
<script>
  const template = document.getElementById("my-paragraph");
  // 获取 template 中的内容
  const templateContent = template.content;
  document.body.appendChild(templateContent);
</script>
1
2
3
4
5
6
7
8
9

# Web Component 实战

实战:将 Custom elements、Shadow DOM、HTML templates 结合起来,实现一个完整的 webComponent 案例。

<html lang="en">
  <body>
    <template id="common-title">
      <h1><slot name="title"></slot></h1>
      <p>hello-world component</p>
    </template>

    <hello-world data-title="my-title">
      <span slot="title">自定义 title</span>
    </hello-world>

    <script>
      // 1、创建一个自定义标签
      // 2、创建 template
      // 3、shadow dom 封装、隔离组件
      class HelloWorld extends HTMLElement {
        constructor() {
          super();
          // 获取 template
          const template = document.getElementById("common-title");
          // shadow dom
          const shadow = this.attachShadow({ mode: "open" });
          shadow.appendChild(template.content);

          // 绑定事件
          this.addEventListener("click", () => {
            alert("click");
          });

          // 获取自定义属性
          const title = this.getAttribute("data-title");
          console.warn("title:", title);
          // 将自定义属性赋值
          this.childNodes[1].textContent = title;
        }
      }
      customElements.define("hello-world", HelloWorld);
    </script>
  </body>
</html>
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

# 开源库

基于 webcomponent 有许多非常成熟的开源库。

# 参考链接

mdn webComponents (opens new window)