Web Components 为什么火不起来?

一听 Web Components ,看起来是很高大上的技术🤔。

它是 W3C 的亲儿子,是浏览器原生支持的组件化标准,由 Custom ElementsShadow DOMHTML Templates 三大底层 API 组成。从 2013 年 Google 首次提出概念到今天,已经过去了整整 13 年。

按理说,一个有着浏览器原生支持、不依赖任何第三方框架、天然跨框架复用的组件标准,应该早就统治前端世界了🤷‍♂️。

但现实是:绝大多数前端工程师依然在用 React 或者 Vue 写组件,Web Components 在实际的商业项目中的采用率,低得令人尴尬。

为什么?因为技术上的正确,从来不等于工程上的好用。接下来我们聊一聊它👇。


开发体验的断崖式落后

Web Components 最大的敌人不是 React,而是它自己那极其原始的开发体验。

我们直接看同一个需求------一个可点击计数器组件------在两套体系下的代码对比:

React 的写法:

tsx 复制代码
function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>点击了 {count} 次</button>;
}

就只有 3 行代码,逻辑清晰,状态驱动视图,任何初级前端都能秒懂🙌。

Web Components 的原生写法:

javascript 复制代码
class MyCounter extends HTMLElement {
  constructor() {
    super();
    this._count = 0;
    this._shadow = this.attachShadow({ mode: 'open' });
    this._render();
  }

  _render() {
    this._shadow.innerHTML = `
      <style>
        button { padding: 8px 16px; cursor: pointer; }
      </style>
      <button>点击了 ${this._count} 次</button>
    `;
    // 每次重新渲染后,必须手动重新绑定事件,因为 innerHTML 会销毁旧的 DOM 节点
    this._shadow.querySelector('button').addEventListener('click', () => {
      this._count++;
      this._render(); // 手动触发重新渲染,没有任何自动化的响应式机制
    });
  }
}

customElements.define('my-counter', MyCounter);

同样的功能,原生 Web Components 的代码量是 React5 倍以上 。而且这里面充斥着极其原始的手动操作:手动拼接 HTML 字符串、手动绑定事件、手动触发重新渲染、手动管理状态。

这不是在写现代化的组件,这是在用 2026 年的浏览器 API 写 2010 年风格的 jQuery 代码😖。


没有内置的响应式系统

ReactuseStateVuerefreactive,它们的核心卖点都是状态驱动视图 :你只管改数据,框架自动帮你更新 DOM

Web Components 的标准里,没有任何内置的响应式机制

你修改了一个属性,DOM 不会自动更新。你必须自己实现 attributeChangedCallback,自己手动去找到对应的 DOM 节点,自己手动去改它的 textContent。当组件的状态变得复杂(比如一个包含 20 个联动字段的表单),你需要手写的同步逻辑会像野草一样疯狂蔓延,最终变成一团无法维护的意大利面条。

有人会说:你可以用 👉 Lit 啊,它给 Web Components 加上了响应式。

没错,Lit 确实极大地改善了开发体验。但问题是:当你必须依赖一个第三方库才能让原生标准变得好用时,这个原生标准的意义在哪里🤷‍♂️? 你用 LitWeb Components,和你用 React 写组件,本质上都是在依赖一个框架。只不过 React 的生态比 Lit 大了几百倍。


Shadow DOM 的样式隔离

Shadow DOMWeb Components 最引以为傲的特性:它提供了真正的样式隔离,组件内部的 CSS 不会泄漏到外部,外部的 CSS 也无法侵入内部。

这在理论上非常美好。但在真实的业务开发中,这种 绝对隔离 会迅速变成不稳定因素。

当你的设计师说全站的按钮统一用品牌蓝时,你发现你根本无法用一个全局的 CSS 变量去穿透 Shadow DOM 的边界(虽然 CSS Custom Properties 可以穿透,但这需要组件内部主动配合暴露接口,大量第三方 Web Components 并没有做这个工作)。

当你想用 Tailwind CSS 的工具类来快速调整组件的样式时,你发现这些 classShadow DOM 里完全失效,因为 Tailwind 生成的样式表根本注入不到 Shadow Root 里面去😖。

隔离是好事,但不可控的隔离是灾难。 ReactVue 的组件没有 Shadow DOM,但通过 CSS ModulesScoped CSS 或者 Tailwind 就能实现足够好的样式隔离,同时保留了全局主题覆盖的灵活性。


不支持 SSR

在 2026 年,服务端渲染(SSR)已经从可选方案变成了项目的标配。ReactNext.jsVueNuxt,它们的 SSR 生态极其成熟。

Web ComponentsSSR 支持,至今依然是一个极其尴尬的半成品。

Custom Elements 本质上依赖浏览器的 JavaScript 引擎来注册和执行。在服务端的 Node.js 环境里,根本没有 customElements.define 这个 API。这意味着你的 Web Components 在服务端只能输出一个空壳标签(如 <my-counter></my-counter>),所有的内容都必须等到客户端 JavaScript 加载并执行后才能渲染。

对于一个重视 SEO 和首屏性能的商业项目来说,这是不可接受的硬伤🤔。


框架复用是一个伪需求

Web Components 最大的宣传卖点是:写一次,在任何框架里复用。

这听起来极其诱人。但你冷静想一想:在真实的项目里,你的团队有多少个项目是同时混用 ReactVue 的?

答案几乎是零,使用场景非常少。

绝大多数公司的前端技术栈是统一的。一旦选定了 React,所有项目都用 React;一旦选定了 Vue,所有项目都用 Vue。在单一技术栈的团队里,跨框架复用是一个根本不存在的需求。你为了满足一个伪需求,去承受 Web Components 那极其糟糕的开发体验,这笔账怎么算都不划算🫵。


那它到底适合在哪里呢?

说了这么多缺陷,Web Components 是不是毫无价值?也并不是🖐️。

在一个极其特定的场景下,它依然是无可替代的最优解:大型企业的跨团队基础设计系统。

当一家公司有几十个前端团队,分别在用 ReactVue、甚至 Angular 时,底层的基础 UI 组件(按钮、输入框、对话框)如果用某个特定框架来写,就必然会排斥其他框架的团队。这个时候,用 Web Components 来构建一套框架无关的基础设计系统,是唯一能让所有团队都无痛接入的方案。

GitHubPrimerAdobeSpectrumSAPUI5------这些顶级企业的设计系统,底层都选择了 Web Components

但请注意,这是一个极少数大型企业才会遇到的问题。对于 99% 的中小型团队来说,直接用 ReactVue 的组件库,永远是性价比最高的选择😀。


一些思考🤔

Web Components 的结果,给所有技术人说明了一件事。

一个技术方案能不能成功,从来不取决于它在标准层面有多正确。W3C 的背书、浏览器的原生支持、理论上的完美架构------这些东西在面对开发日常时,全部苍白无力。

开发者用脚投票。谁的开发体验好、谁的生态强、谁能让我在 deadline 之前把需求交出去,我就用谁🖐️。

ReactVue 赢了,不是因为它们比 Web Components 更正确,而是因为它们更好用,更灵活!

你们同意吗😀?


喜欢我的文章,也欢迎关注我的微信公众号:【前端技术官】。

主要分享:前端架构 · AI 编程 · 职场认知 · 开发者成长

微信扫码关注 👆

不定期更新,不刷屏,聊点真正有用的干货。

相关推荐
Liora_Yvonne1 小时前
从数据库到 Vue 页面:用 LY Fullstack 完成第一个真实全栈业务模块
前端·后端·nestjs
hunterandroid1 小时前
自定义 View 绘制与触摸冲突:从滑动卡顿到事件分发闭环
android·前端
vancece1 小时前
JS实现堆 & 215.数组中的第K个最大元素
java·前端·javascript
newerp1 小时前
语法分析与 AST:Parser 与 go/ast
后端·程序员·go
newerp1 小时前
Go 编译过程全景
后端·程序员·go
SimonKing1 小时前
Apache Fory JSON或许可以替代FastJson
java·后端·程序员
lichenyang4531 小时前
NestJS + Socket.IO 鉴权、用户房间与幂等邀请
前端·后端
paopaokaka_luck1 小时前
基于springboot3+vue3+uniapp的剧本杀预约小程序(AI角色对话、协同过滤算法、地图Api、Echarts图形化分析)
java·前端·spring boot·学习·echarts
lichenyang4531 小时前
React 实时通知与异步竞态处理
前端·后端