Web Components:被大厂冷落却拯救了我们老系统的原生组件方案

高志华
2026-01-13 06:54
阅读 3505

上周五晚上十一点半,我盯着电脑屏幕,心里一万头羊驼奔腾而过——又一个“紧急需求”砸下来:要在三天内把营销页的通用弹窗、登录框、商品卡片统一成一套可复用组件,而且必须兼容我们那套十年前写的 jQuery 门户系统。

作为深圳某传统企业里为数不多还在搞前端的 Java 开发(没错,你没看错,Java 后端被迫写前端),我早就习惯了这种“既要马儿跑又要马儿不吃草”的需求。更离谱的是,产品经理还补了一句:“能不能别用 Vue/React?运维说怕引入新框架影响线上稳定性……”

我当时真想回一句:“那你来写?” 但想了想房贷还没还完,只能默默打开 VS Code。

就在这时,我想起了去年跳槽面试时被问到的一个冷门问题:“了解 Web Components 吗?” 当时支支吾吾答得不太好,结果那家腾讯系公司直接把我挂了。回来后我狠狠补了一波,没想到今天居然派上用场了。


为什么我们最终选了 Web Components?

先说结论:Web Components 是一套浏览器原生支持的组件化标准,不需要任何框架就能实现封装、复用和隔离。

对我们这种夹在“老系统不能动”和“新需求天天加”之间的团队来说,它简直是天降神兵。原因有三:

  1. 零依赖:不用打包、不引 npm 包、不污染全局变量。运维看了直呼“稳”。
  2. 跨框架兼容:Vue、React、Angular,甚至纯 HTML 页面都能直接用。
  3. 天然 Shadow DOM 隔离:样式不会串,再也不用担心 PM 改个 class 把整个页面搞崩。

最关键的是——它能让我这个 Java 开发在不碰构建工具链的情况下,写出像模像样的组件。毕竟我连 Webpack 的 loader 和 plugin 都分不太清……


实战:三天重构营销组件

我们第一个要改造的是“通用登录弹窗”。以前是复制粘贴式开发,每个活动页都有一套自己的登录逻辑,CSS 样式还互相冲突。用户点开 A 活动登录,结果弹出 B 活动的样式,测试直接提了 P0 级 Bug。

第一步:定义组件

Web Components 基于三个核心技术:

  • Custom Elements(自定义标签)
  • Shadow DOM(样式作用域隔离)
  • HTML Templates(模板复用)

我先写了个最简版:

class LoginModal extends HTMLElement {
  constructor() {
    super();
    // 创建 Shadow DOM
    const shadow = this.attachShadow({ mode: 'open' });
    
    // 定义内部结构和样式
    shadow.innerHTML = `
      <style>
        .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); }
        .modal.show { display: block; }
        .content { background: white; padding: 24px; margin: 100px auto; max-width: 400px; border-radius: 8px; }
        input { width: 100%; padding: 8px; margin: 8px 0; }
        button { background: #0066cc; color: white; border: none; padding: 10px; width: 100%; }
      </style>
      <div class="modal" id="modal">
        <div class="content">
          <h3>登录</h3>
          <input type="text" placeholder="手机号" id="phone">
          <input type="password" placeholder="密码" id="pwd">
          <button id="submit">立即登录</button>
        </div>
      </div>
    `;
  }

  // 对外暴露方法
  show() {
    this.shadowRoot.getElementById('modal').classList.add('show');
  }

  connectedCallback() {
    // 绑定事件(注意:必须绑定在 shadowRoot 内部元素上!)
    this.shadowRoot.getElementById('submit').addEventListener('click', () => {
      const phone = this.shadowRoot.getElementById('phone').value;
      const pwd = this.shadowRoot.getElementById('pwd').value;
      
      // 调用后端接口(这里简化)
      fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify({ phone, pwd })
      }).then(res => {
        if (res.ok) {
          alert('登录成功!');
          this.hide();
        }
      });
    });
  }

  hide() {
    this.shadowRoot.getElementById('modal').classList.remove('show');
  }
}

// 注册自定义元素
customElements.define('login-modal', LoginModal);

然后在 HTML 里直接用:

<login-modal id="loginComp"></login-modal>

<script>
  // 任意地方调用
  document.getElementById('loginBtn').addEventListener('click', () => {
    document.getElementById('loginComp').show();
  });
</script>

效果立竿见影:样式完全隔离,逻辑集中管理,连测试都说这次没出现“登录框跑到页面底部”的诡异 Bug。


踩过的坑与调试技巧

当然,过程没那么顺利。比如:

  • 事件无法冒泡到外部:因为 Shadow DOM 天然隔离,外部 document.addEventListener 捕获不到内部点击。解决方案是组件内部主动派发自定义事件:

    this.dispatchEvent(new CustomEvent('login-success', { detail: { userId: 123 } }));
    
  • IE 兼容性?别想了:我们内部系统最低要求 Chrome 70+,所以直接放弃 polyfill。省心!

  • 调试困难:Chrome DevTools 默认不展开 Shadow DOM。需要在设置里勾选 "Show user agent shadow DOM",或者直接右键 -> "Show Shadow DOM"。

另外,不要试图在 Shadow DOM 里用全局 CSS 变量——除非你显式传递进去。我们后来统一用 <style> 内联写死,反而更可控。


性能 & 资源对比

为了说服技术负责人,我还做了个小对比:

方案 是否需构建 体积 兼容老系统 学习成本 组件隔离
React/Vue 是 ~40KB+ 困难 高 依赖框架机制
jQuery 插件 否 ~5KB 容易 低 无(极易样式冲突)
Web Components 否 ~2KB 极容易 中 原生 Shadow DOM

关键是那个“是否需构建”——运维老大看到这一栏眼睛都亮了。他说:“终于有个不用装 node_modules 的前端方案了!”


求职视角:这玩意值得学吗?

说实话,大厂现在主推的还是 React/Vue 生态。我在 BOSS 直聘上搜“Web Components”,岗位少得可怜,基本集中在传统企业或政府项目。

但它绝对是个“差异化竞争力”。
面试官一听你会 Web Components,大概率会追问细节:“Shadow DOM 如何穿透?”、“如何做服务端渲染?”、“和微前端怎么结合?” —— 这些问题答好了,能瞬间拉开和其他候选人的差距。

而且,很多微前端方案(比如 Single-SPA、Qiankun)底层都用到了 Custom Elements。理解 Web Components,等于摸到了现代前端架构的一块基石。

我自己就是因为这次实战,被隔壁组挖去参与一个跨部门组件库项目。领导说:“你那个登录框,能不能做成公司级通用组件?” —— 这不比天天改 Bug 强?


最后一点真心话

Web Components 不是银弹。如果你在做一个全新 SPA 应用,大概率还是 React/Vue 更高效。但如果你和我一样:

  • 被困在老旧系统里
  • 想快速交付可复用 UI
  • 又不想惹怒运维和测试

那它真的值得一试。原生、轻量、无依赖,这才是“渐进式增强”的正确姿势。

至于资源?官方文档其实挺全(MDN - Web Components),再配合 ChatGPT 写个基础模板,半小时就能跑起来。Claude 甚至还能帮你生成完整的 TypeScript 版本。

现在,每当我看到营销同事在群里说“新活动直接用了登录组件,没出 bug”,我就觉得——值了。

哪怕只是个 Java 开发,也能用原生 JS 搞出点名堂。毕竟在深圳这片土地上,能解决问题的技术,就是好技术。

评论 0

最热最新
暂无评论
高志华Lv.1
0
影响力
0
文章
0
粉丝