Web Components:原生组件化开发,你真的不需要框架吗?

心想事成
2026-04-16 14:36
阅读 1222

大家好,我是阿杰,一名在大厂干了三年前端的老兵,业余时间也在B站做技术分享。最近不少刚入门的同学问我:“现在都2024年了,React/Vue 那么火,为什么还要学 Web Components?”其实这个问题我也在面试中被问过——没错,Web Components 已经悄悄成为大厂前端面试的新考点

今天这篇教程,就是专门为零基础朋友准备的。我会用最直白的语言、最少的术语,带你从零开始搞懂 Web Components。更重要的是,我会告诉你:它和 React 有什么区别?为什么连 Python 开发者也开始关注它?以及如何用 Claude Code 辅助你快速上手?


一、Web Components 到底是什么?

简单说:Web Components 是浏览器原生支持的“自定义 HTML 标签”能力

你有没有想过,为什么 <button><input> 这些标签可以直接用?因为浏览器内置了它们。而 Web Components 让你也能“造”出自己的标签,比如 <my-header><user-card>,而且不用依赖 React、Vue 等任何框架!

我当初学的时候,以为这东西很冷门。结果后来发现,像 YouTube、GitHub、Salesforce 这些大厂早已在生产环境大量使用。更关键的是——它性能极高,因为是浏览器原生实现,没有虚拟 DOM 的开销。


二、环境准备:5分钟搞定开发环境

好消息是:你几乎不需要额外安装任何东西!只要你的电脑有:

  • 最新版 Chrome / Edge / Firefox(都已全面支持)
  • 一个文本编辑器(VS Code、记事本都行)

💡 避坑指南:别装什么“Web Components 框架”!我们要学的是原生写法,这才是面试官想考的。

创建一个项目文件夹,新建 index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>我的第一个 Web Component</title>
</head>
<body>
  <!-- 我们的自定义组件会放这里 -->
  <my-greeting name="小明"></my-greeting>

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

再新建 main.js,我们就准备好了!


三、三大核心概念,一张表说清楚

Web Components 由三个原生 API 组成。别怕,其实很简单:

技术 作用 类比理解
Custom Elements 定义新 HTML 标签名 就像给 HTML “注册”一个新零件
Shadow DOM 实现样式和 DOM 隔离 组件内部是个“独立小世界”,外面样式进不来
HTML Templates 声明可复用的 HTML 结构 先写好“模具”,需要时再复制出来

下面逐个拆解,带代码实操。


1. Custom Elements:定义你的第一个组件

main.js 中写下这段代码:

class MyGreeting extends HTMLElement {
  constructor() {
    super(); // 必须调用父类构造器
    this.innerHTML = `<h1>Hello, ${this.getAttribute('name')}!</h1>`;
  }
}

// 注册组件:告诉浏览器 "<my-greeting>" 对应哪个类
customElements.define('my-greeting', MyGreeting);

刷新页面,你会看到:Hello, 小明!

新手注意

  • 组件名必须包含 -(短横线),比如 user-card,不能叫 userCard
  • getAttribute 用来读取 HTML 属性(如 name="小明"

2. Shadow DOM:让样式不打架

假设你在全局写了 h1 { color: red; },会影响组件内的 h1 吗?不会! 因为我们可以用 Shadow DOM 隔离。

修改 MyGreeting 类:

class MyGreeting extends HTMLElement {
  constructor() {
    super();
    // 创建 Shadow DOM
    const shadow = this.attachShadow({ mode: 'open' });
    
    // 内部 HTML 和 CSS
    shadow.innerHTML = `
      <style>
        h1 { color: blue; font-family: Arial; }
      </style>
      <h1>Hello, ${this.getAttribute('name')}!</h1>
    `;
  }
}

现在,无论页面其他地方怎么改 h1 样式,这个组件始终是蓝色!

💡 性能优化提示:Shadow DOM 能避免样式污染,减少重绘重排,提升渲染性能。


3. Template:复用结构模板

如果组件结构复杂,每次都拼字符串很麻烦。这时用 <template>

index.html<head> 里加:

<template id="greeting-template">
  <style>
    h1 { color: green; }
  </style>
  <h1>Hello, <span class="name"></span>!</h1>
</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);
    
    // 设置名字
    instance.querySelector('.name').textContent = this.getAttribute('name');
    
    shadow.appendChild(instance);
  }
}

customElements.define('my-greeting', MyGreeting);

这样,HTML 结构和逻辑分离,代码更清晰!


四、实战项目:做一个用户信息卡片

现在,我们综合运用所学,做一个 <user-card> 组件。

步骤 1:HTML 结构

<user-card 
  avatar="https://example.com/avatar.jpg"
  name="张三"
  bio="前端工程师 | 爱好编程和咖啡">
</user-card>

步骤 2:定义组件

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

    // 使用模板方式(也可直接拼字符串)
    shadow.innerHTML = `
      <style>
        .card {
          border: 1px solid #ddd;
          border-radius: 8px;
          padding: 16px;
          max-width: 300px;
          font-family: sans-serif;
        }
        img {
          width: 60px;
          height: 60px;
          border-radius: 50%;
          object-fit: cover;
        }
        .info { margin-top: 12px; }
        h2 { margin: 8px 0 4px; }
        p { color: #666; margin: 0; }
      </style>
      <div class="card">
        <img src="${this.getAttribute('avatar')}" alt="头像">
        <div class="info">
          <h2>${this.getAttribute('name')}</h2>
          <p>${this.getAttribute('bio')}</p>
        </div>
      </div>
    `;
  }
}

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

步骤 3:测试效果

在页面多放几个:

<user-card avatar="a.jpg" name="李四" bio="设计师"></user-card>
<user-card avatar="b.jpg" name="王五" bio="Python后端"></user-card>

每个卡片完全独立,样式互不影响!

🎯 面试题挑战
Q:Web Components 和 React 组件有什么本质区别?
A:React 组件是 JS 函数 + 虚拟 DOM,依赖运行时;Web Components 是浏览器原生能力,无需框架,性能更高,但生态较弱。


五、新手常见问题解答

❓ 1. 能和 React/Vue 一起用吗?

可以! 很多公司用 Web Components 封装底层 UI(如按钮、弹窗),再在 React 中调用。例如:

// React 组件中直接使用
function App() {
  return <user-card name="React用户" />;
}

❓ 2. 数据怎么更新?有状态管理吗?

原生 Web Components 没有内置状态系统。但你可以:

  • 监听属性变化(用 attributeChangedCallback
  • 或结合轻量库(如 Lit)简化开发

❓ 3. Python 开发者为什么要关心?

现在很多 Python Web 框架(如 Django、Flask)输出的是服务端 HTML。用 Web Components 可以在后端直接嵌入交互组件,无需引入前端构建工具链,特别适合快速原型开发!

❓ 4. 如何用 Claude Code 辅助学习?

我在 B站 视频里常用 Claude 生成 Web Components 示例代码。比如输入:

“用原生 Web Components 写一个带计数器的按钮组件”

它能快速给你完整代码,省去查文档时间。但记得自己动手改几遍,才能真正掌握!


六、下一步学习建议

如果你已经跑通了上面的例子,恭喜你入门了!接下来可以:

  1. 深入学习生命周期:了解 connectedCallbackdisconnectedCallback 等钩子
  2. 尝试 Lit 库:Google 出品的轻量 Web Components 库,语法更简洁
  3. 对比 React:试着把同一个组件分别用 React 和 Web Components 实现,感受差异
  4. 参与开源:看看 GitHub 上哪些项目用了 Web Components(如 Shoelace、FAST)

⚠️ 最后提醒:Web Components 不是 React 的替代品,而是另一种思路。大厂往往两者并用——核心交互用 React,基础 UI 用 Web Components 提升性能。


结语

我当初学前端时,只盯着 React,觉得原生 DOM 操作“过时了”。直到一次性能优化任务,才意识到:有时候,最简单的原生方案,反而是最高效的

Web Components 就是这样一个“返璞归真”的技术。它可能不会让你立刻找到工作,但一定能让你在面试中脱颖而出,尤其是在考察“底层原理”和“性能优化”时。

如果你觉得这篇教程有帮助,欢迎去 B站 搜“阿杰前端课”,我会持续更新更多实战内容。下期见!

评论 0

最热最新
暂无评论
心想事成Lv.1
0
影响力
0
文章
0
粉丝