Web Components:原生组件化开发新趋势

大数据AI
2025-12-15 20:49
阅读 245

大家好,我是小林,一名211高校的计算机专业研究生,平时喜欢写技术博客帮助刚入门的小伙伴。最近有不少学弟学妹问我:“现在前端框架这么多,React、Vue满天飞,有没有更‘原生’一点的组件化方案?”这让我想起自己当初学前端时也有同样的困惑——是不是非得用 React 才能写组件?

今天这篇教程,我就带大家认识一个不需要任何框架就能实现组件化的技术:Web Components。它是由浏览器原生支持的标准,让你像搭积木一样构建可复用的 UI 元素。无论你是后端同学想快速写点前端界面,还是零基础小白想理解“组件”到底是什么,这篇文章都适合你!


一、Web Components 是什么?能干什么?

简单说,Web Components 就是浏览器自带的“组件系统”。你可以把它想象成一个自定义的 HTML 标签,比如 <my-button><user-card>,它内部封装了 HTML 结构、CSS 样式和 JavaScript 行为,用起来就像 <div> 一样简单。

为什么值得关注?

  • 无需依赖 React/Vue:纯原生,现代浏览器都支持
  • 天然隔离:样式和逻辑不会污染全局(后面会讲“Shadow DOM”)
  • 跨框架兼容:你写的 Web Component 可以在 React、Vue 甚至纯 HTML 项目中直接使用
  • 对后端友好:如果你是后端开发者,不用学复杂框架也能写出结构清晰的前端界面

我当初第一次看到 Web Components 时,第一反应是:“原来不用 React 也能写组件?!”后来发现,很多大厂(比如 GitHub、Salesforce)都在生产环境用了它。


二、环境准备:5 分钟快速上手

好消息是:你几乎不需要任何配置!

所需工具

工具 说明
浏览器 Chrome、Edge、Firefox、Safari 最新版(都支持)
代码编辑器 VS Code、Sublime Text 或记事本都行
本地服务器(可选) Live Server 插件或 Python 的 http.server

第一步:创建一个 HTML 文件

新建一个 index.html,内容如下:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Web Components 入门</title>
</head>
<body>
  <h1>我的第一个 Web Component</h1>
  
  <!-- 这里将使用我们自定义的组件 -->
  <my-greeting name="小林"></my-greeting>

  <script src="greeting.js"></script>
</body>
</html>

第二步:创建组件文件

新建 greeting.js,先留空,下一节我们来填内容。

⚠️ 注意:由于安全限制,不能直接双击打开 HTML 文件!需要用本地服务器运行。
快速启动方法(任选其一):

  • VS Code 安装 Live Server 插件,右键“Open with Live Server”
  • 终端执行:python3 -m http.server 8000(Mac/Linux)或 python -m http.server 8000(Windows)

三、核心概念:三大支柱

Web Components 由三个核心技术组成,记住这个口诀:C-S-T

缩写 全称 作用
C Custom Elements 自定义 HTML 标签
S Shadow DOM 隔离样式和 DOM
T Template 定义可复用的 HTML 模板

下面我用最通俗的方式解释它们。

1. Custom Elements(自定义元素)

就是让你能写 <my-button> 这种标签。浏览器不认识它?没关系,我们“教”它!

// greeting.js
class MyGreeting extends HTMLElement {
  constructor() {
    super(); // 必须调用
    this.innerHTML = '<p>Hello, 世界!</p>';
  }
}

// 注册组件
customElements.define('my-greeting', MyGreeting);

刷新页面,你会看到 “Hello, 世界!”。但名字是写死的,怎么传参数?

2. 使用属性传参

HTML 标签可以加属性,比如 <my-greeting name="张三">。我们在 JS 里读取它:

class MyGreeting extends HTMLElement {
  constructor() {
    super();
    // 获取 name 属性
    const name = this.getAttribute('name') || '陌生人';
    this.innerHTML = `<p>Hello, ${name}!</p>`;
  }
}
customElements.define('my-greeting', MyGreeting);

现在 <my-greeting name="小林"> 就会显示 “Hello, 小林!”

3. Shadow DOM:样式的“结界”

假设你在全局写了 p { color: red; },会不会影响组件内的 <p>不会! 因为 Shadow DOM 创建了一个“隔离空间”。

修改 greeting.js

class MyGreeting extends HTMLElement {
  constructor() {
    super();
    
    // 创建 Shadow DOM
    const shadow = this.attachShadow({ mode: 'open' });
    
    const name = this.getAttribute('name') || '陌生人';
    shadow.innerHTML = `
      <style>
        p { 
          color: blue; 
          font-weight: bold;
          /* 这个样式只在组件内部生效 */
        }
      </style>
      <p>Hello, ${name}!</p>
    `;
  }
}
customElements.define('my-greeting', MyGreeting);

即使你在 <style> 里写 p { color: green; },组件内的文字依然是蓝色!这就是 Shadow DOM 的魔力。

4. Template:更优雅的模板写法

当结构复杂时,用字符串拼接很麻烦。我们可以用 <template> 标签预定义结构。

index.html<head> 中加入:

<template id="greeting-template">
  <style>
    p { color: purple; }
  </style>
  <p>Hello, <span id="name-slot"></span>!</p>
</template>

然后在 JS 中克隆它:

class MyGreeting extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    
    // 克隆模板
    const template = document.getElementById('greeting-template');
    const instance = template.content.cloneNode(true);
    
    // 填充名字
    const name = this.getAttribute('name') || '陌生人';
    instance.querySelector('#name-slot').textContent = name;
    
    shadow.appendChild(instance);
  }
}
customElements.define('my-greeting', MyGreeting);

这样 HTML 和 JS 分离,代码更清晰!


四、实战:做一个“用户信息卡片”

我们来做一个稍微复杂的组件:显示用户头像、姓名和简介。

步骤 1:HTML 结构

<!-- index.html -->
<user-card 
  avatar="https://via.placeholder.com/50" 
  name="小林" 
  bio="前端爱好者,爱写博客">
</user-card>

步骤 2:编写组件(user-card.js)

class UserCard extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });

    // 获取属性
    const avatar = this.getAttribute('avatar') || '';
    const name = this.getAttribute('name') || '匿名用户';
    const bio = this.getAttribute('bio') || '暂无简介';

    shadow.innerHTML = `
      <style>
        .card {
          border: 1px solid #ddd;
          border-radius: 8px;
          padding: 16px;
          max-width: 300px;
          font-family: Arial, sans-serif;
        }
        .header {
          display: flex;
          align-items: center;
          gap: 12px;
        }
        .avatar {
          width: 50px;
          height: 50px;
          border-radius: 50%;
        }
        .name {
          font-size: 18px;
          font-weight: bold;
        }
        .bio {
          margin-top: 12px;
          color: #555;
        }
      </style>
      <div class="card">
        <div class="header">
          <img class="avatar" src="${avatar}" />
          <div class="name">${name}</div>
        </div>
        <div class="bio">${bio}</div>
      </div>
    `;
  }
}

customElements.define('user-card', UserCard);

步骤 3:引入脚本

index.html<body> 底部加上:

<script src="user-card.js"></script>

刷新页面,一个漂亮的用户卡片就出现了!

💡 小技巧:你可以把这个组件复制到任何 HTML 页面,甚至 React 项目里直接用!因为它是原生的。


五、新手常见问题解答

Q1:Web Components 和 React 组件有什么区别?

对比项 Web Components React 组件
依赖 无,浏览器原生支持 需要 React 库
学习成本 低(只需 JS + HTML) 较高(JSX、状态管理等)
生态 较小 非常丰富
适用场景 简单 UI 组件、跨框架复用 复杂交互应用

Q2:后端同学适合用 Web Components 吗?

非常适合! 如果你只是需要展示数据、做简单交互(比如表单、卡片、按钮),完全不用学 React。直接用 Web Components + 原生 JS 就能搞定,省时省力。

Q3:浏览器兼容性如何?

现代浏览器(Chrome 54+、Firefox 63+、Safari 10.1+、Edge 79+)都支持。如果需要兼容老版本 IE,可以用 polyfill

Q4:怎么响应属性变化?

目前我们的组件只在初始化时读取属性。如果后续属性变了(比如通过 JS 修改),组件不会自动更新。解决方法是监听属性变化:

static get observedAttributes() {
  return ['name', 'bio']; // 监听哪些属性
}

attributeChangedCallback(name, oldValue, newValue) {
  if (oldValue !== newValue) {
    // 重新渲染
    this.render();
  }
}

完整实现略复杂,初学者可先忽略,知道有这个机制就行。


六、学习建议与下一步

Web Components 是一个“轻量级”的组件化方案,特别适合以下场景:

  • 写通用 UI 库(比如按钮、弹窗)
  • 后端快速搭建管理界面
  • 在多个不同技术栈的项目中复用组件

下一步可以学:

  1. 生命周期方法connectedCallbackdisconnectedCallback
  2. 插槽(Slot):实现类似 Vue 的 <slot> 功能
  3. 与框架集成:如何在 React 中使用 Web Components
  4. 工具链:用 Lit(轻量库)简化开发

我当初就是从 Web Components 入门,再过渡到 React 的。理解了“组件”的本质,学任何框架都会更快!


希望这篇教程能帮你打开原生组件化的大门。记住:技术没有高低,只有合适与否。 如果你的需求简单,Web Components 可能就是那把最趁手的“瑞士军刀”。

有问题欢迎留言讨论!我是小林,一个爱写代码也爱写教程的研究生,我们下期见!

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝