JavaScript Web Components 教程:构建可复用自定义组件

引言

Web Components 是一套由浏览器原生支持的 Web API,它允许开发者创建可重用、封装良好的定制 HTML 元素,从而实现组件化的前端开发模式。通过 Web Components ,我们可以定义新的、功能丰富的用户界面元素,并且它们可以像标准HTML元素一样在任何地方被轻易地使用和组合。本教程将带你入门 JavaScript Web Components 的世界,了解其核心概念并实战创建一个基本的自定义组件。

Web Components 组件体系

Web Components 主要由以下四个核心技术构成:

1. Custom Elements(自定义元素)

  • 允许开发者扩展HTML元素集合,通过定义新的标签来创建自定义组件。
javascript 复制代码
class MyCustomElement extends HTMLElement {
 constructor() {
   super();
   // 构造逻辑...
 }
 
 connectedCallback() {
   // 当 custom element首次被插入文档DOM时,被调用
 }
 
 disconnectedCallback() {
   // 当 custom element从文档DOM中删除时,被调用
 }
 
 adoptedCallback() {
   // 当 custom element被移动到新的文档时,被调用
 }
 
 attributeChangedCallback() {
   // 当 custom element增加、删除、修改自身属性时,被调用
 }
}
customElements.define('my-component', MyCustomElement);

2. Shadow DOM(影子DOM)

  • 提供了封装样式和结构的能力,使组件内部的CSS样式不会影响到外部环境,反之亦然。
javascript 复制代码
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `
 <style>
   /* 组件内部样式 */
 </style>
 <div class="content">...</div>
`;

3. HTML Templates(HTML模板)

  • 使用<template><slot>元素定义组件的内容和可替换区域。
html 复制代码
<template id="my-template">
  <style>
    /* 组件样式 */
  </style>
  <div class="container">
    <slot></slot> <!-- 这里可以插入其他元素 -->
  </div>
</template>

4. HTML Imports(已废弃,现推荐使用模块系统)

  • 原本用于导入HTML文件作为组件的载体,但在现代浏览器中,我们通常使用ES6模块或其他模块加载机制来引入组件脚本。

创建一个简单的 Web Component

下面,我们将一步步创建一个名为my-counter的基本计数器组件:

html 复制代码
<!-- my-counter.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Counter Web Component</title>
  <script type="module">
    class MyCounter extends HTMLElement {
      constructor() {
        super();
        this._count = 0;
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.appendChild(this.createTemplate());
        this.incrementBtn = this.shadowRoot.querySelector('.increment');
        this.decrementBtn = this.shadowRoot.querySelector('.decrement');
        this.counterDisplay = this.shadowRoot.querySelector('#counter');
      }

      createTemplate() {
        const template = document.createElement('template');
        template.innerHTML = `
          <style>
            .counter-container {
              display: flex;
              align-items: center;
            }
            button {
              margin: 0 10px;
            }
          </style>
          <div class="counter-container">
            <button class="increment">+</button>
            <span id="counter">0</span>
            <button class="decrement">-</button>
          </div>
        `;
        return template.content.cloneNode(true);
      }

      connectedCallback() {
        this.incrementBtn.addEventListener('click', () => this.increment());
        this.decrementBtn.addEventListener('click', () => this.decrement());
      }

      increment() {
        this._count++;
        this.updateCount();
      }

      decrement() {
        if (this._count > 0) {
          this._count--;
          this.updateCount();
        }
      }

      updateCount() {
        this.counterDisplay.textContent = this._count;
      }
    }

    customElements.define('my-counter', MyCounter);
  </script>
</head>
<body>
  <my-counter></my-counter>
</body>
</html>

在这个例子中,我们定义了一个MyCounter类,它继承自HTMLElement并实现了构造函数、生命周期钩子以及一些方法来控制计数器的行为。组件内部使用了 Shadow DOM,并且包含两个按钮和一个显示计数值的<span>元素。

使用Web Components

现在你已经创建了一个 Web Component ,你可以像普通 HTML 元素那样在页面中使用它:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Using My Counter Component</title>
  <link rel="import" href="my-counter.html"> <!-- 如果不使用模块,则通过链接引入 -->
</head>
<body>
  <h1>Counters:</h1>
  <my-counter></my-counter>
  <my-counter></my-counter>
</body>
</html>

写在最后

Web ComponentsWeb 开发带来了一种强大的组件化方式,让开发者能够更好地组织代码,提升代码复用性和维护性。通过深入学习和实践,你会发现 Web Components 在现代前端项目中的巨大价值。

喜欢的话帮忙点个赞 + 关注吧,将持续更新 JavaScript 相关的文章,还可以关注我的公众号 梁三石FE ,感谢您的关注~

相关推荐
Dxy12393102169 小时前
MySQL索引完整教程:创建、查看、修改、删除与日常管理
前端·javascript·mysql
端庄的战斗机11 小时前
javascript 设计模式(文章很长,请自备瓜子,水果和眼药水)
开发语言·javascript·设计模式
前端毕业班13 小时前
uni-app 小程序支持 teleport 了
前端·javascript·vue.js
东风破_14 小时前
LLM 为什么记不住你?无状态、messages 和上下文管理
javascript·人工智能
Hilaku14 小时前
前端架构师的克制:什么时候该坚决对新技术说不?
前端·javascript·程序员
古夕15 小时前
多应用同域部署下 Favicon 异常问题排查与治理
前端·javascript
逗逗豆巴吧15 小时前
WPS 加载项中实现当前文档直接上传
前端·javascript·ecmascript 6
妙码生花15 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(二十一):网络请求封装优化
前端·javascript·vue.js
用户114818678948415 小时前
普通Fetch、Fetch流式、Axios、SSE:谁才是流式输出的正确操作?
前端·javascript
谷哥的小弟16 小时前
TypeScript数组类型
javascript·typescript