Skip to content

Web Component 开发实现流程

Web Component 是一种用于创建可重用自定义元素的技术,让开发者可以构建自己的 HTML 元素,就像使用原生 HTML 标签一样。

核心概念

Web Component 基于以下四个核心技术:

  1. 自定义元素 (Custom Elements) - 允许开发者定义自己的 HTML 元素
  2. 影子 DOM (Shadow DOM) - 提供封装,将组件的样式和结构与页面其他部分隔离
  3. HTML 模板 (HTML Templates) - 定义可重用的标记结构
  4. ES 模块 (ES Modules) - 用于导入和导出组件

开发流程

1. 定义自定义元素

首先,我们需要创建一个类来定义自定义元素的行为:

javascript
class MyElement extends HTMLElement {
  constructor() {
    super()
    // 元素初始化代码
  }

  // 当元素被添加到 DOM 时调用
  connectedCallback() {
    // 元素被添加到页面时执行的代码
  }

  // 当元素从 DOM 中移除时调用
  disconnectedCallback() {
    // 元素被移除时执行的代码
  }

  // 当元素的属性发生变化时调用
  attributeChangedCallback(name, oldValue, newValue) {
    // 属性变化时执行的代码
  }

  // 定义需要监听变化的属性
  static get observedAttributes() {
    return ['attribute1', 'attribute2']
  }
}

然后,使用 customElements.define() 方法注册自定义元素:

javascript
// 注册自定义元素,名称必须包含连字符
customElements.define('my-element', MyElement)

2. 使用影子 DOM

影子 DOM 允许我们创建一个隔离的 DOM 树,防止组件的样式和结构影响到页面的其他部分:

javascript
class MyElement extends HTMLElement {
  constructor() {
    super()

    // 创建影子 DOM
    const shadow = this.attachShadow({ mode: 'open' })

    // 创建元素
    const container = document.createElement('div')
    container.textContent = 'Hello, Web Component!'

    // 创建样式
    const style = document.createElement('style')
    style.textContent = `
      div {
        padding: 10px;
        background-color: #f0f0f0;
        border-radius: 5px;
      }
    `

    // 将元素和样式添加到影子 DOM
    shadow.appendChild(style)
    shadow.appendChild(container)
  }
}

3. 使用 HTML 模板

HTML 模板允许我们定义可重用的标记结构:

html
<!-- 在 HTML 文件中定义模板 -->
<template id="my-element-template">
  <style>
    div {
      padding: 10px;
      background-color: #f0f0f0;
      border-radius: 5px;
    }
  </style>
  <div>
    <slot name="title">默认标题</slot>
    <slot>默认内容</slot>
  </div>
</template>
javascript
class MyElement extends HTMLElement {
  constructor() {
    super()

    const shadow = this.attachShadow({ mode: 'open' })

    // 获取模板内容
    const template = document.getElementById('my-element-template')
    const templateContent = template.content

    // 克隆模板内容并添加到影子 DOM
    shadow.appendChild(templateContent.cloneNode(true))
  }
}

4. 使用组件

html
<!DOCTYPE html>
<html>
  <head>
    <script src="my-element.js"></script>
  </head>
  <body>
    <my-element>
      <span slot="title">自定义标题</span>
      <p>这是自定义内容</p>
    </my-element>
  </body>
</html>

进阶特性

生命周期回调

  • constructor():元素实例被创建时调用
  • connectedCallback():元素被插入到 DOM 时调用
  • disconnectedCallback():元素从 DOM 中移除时调用
  • adoptedCallback():元素被移动到新的文档时调用
  • attributeChangedCallback(name, oldValue, newValue):元素的属性发生变化时调用

最佳实践

  1. 命名规范:自定义元素名称必须包含连字符(如 my-element),以避免与标准 HTML 标签冲突
  2. 影子 DOM 模式open 模式允许外部 JavaScript 访问影子 DOM,closed 模式则不允许
  3. 渐进增强:确保组件在不支持 Web Component 的浏览器中有降级方案
  4. 样式封装:利用影子 DOM 的样式隔离特性,避免全局样式污染