Web Components:原生组件化开发,你真的不需要框架吗?
大家好,我是211高校计算机专业的研二学生,平时喜欢在 GitHub 上写技术博客,帮助刚入门的学弟学妹少走弯路。最近有不少初学者问我:“现在前端框架这么多,还有必要学 Web Components 吗?”我当初学的时候也这么疑惑过——直到我发现,Web Components 是浏览器原生支持的组件化方案,不依赖 Vue、React 等任何框架,却能实现同样的封装与复用能力。
今天这篇教程,就带零基础的你,从零开始掌握 Web Components 的核心用法,并动手做一个可复用的“点赞按钮”组件。全程不用 npm、不用构建工具,只用一个 HTML 文件就能跑起来!
一、什么是 Web Components?为什么值得学?
Web Components 是一套由 W3C 标准定义的浏览器原生 API,包含三个核心技术:
- Custom Elements(自定义元素):让你创建自己的 HTML 标签,比如
<my-button>。 - Shadow DOM(影子 DOM):提供样式和 DOM 的封装,避免外部 CSS 干扰组件内部。
- HTML Templates(模板):用
<template>标签预定义 HTML 结构,按需渲染。
✅ 优势:无需打包、无运行时开销、跨框架兼容(Vue/React/Angular 都能用!)
❌ 局限:IE 不支持(但现代项目基本不用 IE 了)
我当初第一次看到 <custom-card></custom-card> 能直接在页面上工作时,简直惊呆了——原来浏览器自己就能做组件化!
二、环境准备:5 分钟快速上手
好消息是:你不需要安装 Node.js、Webpack 或任何构建工具!
只需:
- 一个现代浏览器(Chrome / Edge / Firefox / Safari)
- 一个文本编辑器(VS Code、记事本都行)
- 本地打开 HTML 文件(或通过
live-server启动简易服务)
🔧 推荐工具:如果你习惯命令行,可以用
npx live-server快速启动本地服务(需先安装 Node.js)。但直接双击 HTML 文件也能运行大部分功能。
三、三大核心概念详解(附代码)
1. 自定义元素(Custom Elements)
通过 customElements.define() 注册一个新标签。
<!-- index.html -->
<script>
class MyButton extends HTMLElement {
constructor() {
super();
this.innerHTML = '<button>点我</button>';
}
}
// 注册标签名为 my-button
customElements.define('my-button', MyButton);
</script>
<my-button></my-button>
💡 注意:自定义标签名必须包含连字符
-,这是浏览器区分原生标签和自定义标签的规则。
2. Shadow DOM:隔离样式与结构
上面的例子有个问题:如果外部有 button { color: red; },按钮颜色会被污染。用 Shadow DOM 解决:
class MyButton extends HTMLElement {
constructor() {
super();
// 创建 Shadow Root
const shadow = this.attachShadow({ mode: 'open' });
// 定义内部结构
shadow.innerHTML = `
<style>
button {
background: #4CAF50;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
}
button:hover { opacity: 0.8; }
</style>
<button>👍 点赞</button>
`;
}
}
现在,外部样式完全无法影响这个按钮!这就是 Shadow DOM 的封装性。
3. HTML Template:预定义结构
对于复杂组件,直接写字符串容易出错。可以用 <template> 提前写好结构:
<template id="my-button-template">
<style>
button { background: #2196F3; color: white; }
</style>
<button>❤️ 喜欢</button>
</template>
<script>
class MyButton extends HTMLElement {
constructor() {
super();
const template = document.getElementById('my-button-template');
const content = template.content.cloneNode(true);
this.attachShadow({ mode: 'open' }).appendChild(content);
}
}
customElements.define('my-button', MyButton);
</script>
✅
cloneNode(true)表示深拷贝模板内容,避免多次使用时互相干扰。
四、实战:做一个带计数功能的点赞组件
现在,我们整合所有知识,做一个真正的组件:点击按钮,数字+1。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Web Components 实战</title>
</head>
<body>
<like-button></like-button>
<like-button></like-button>
<template id="like-button-template">
<style>
.container {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: Arial;
}
button {
background: #ff4757;
color: white;
border: none;
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
}
span { font-weight: bold; }
</style>
<div class="container">
<button>👍</button>
<span>0</span>
</div>
</template>
<script>
class LikeButton extends HTMLElement {
constructor() {
super();
const template = document.getElementById('like-button-template');
const content = template.content.cloneNode(true);
this.shadow = this.attachShadow({ mode: 'open' });
this.shadow.appendChild(content);
// 获取按钮和计数器
this.button = this.shadow.querySelector('button');
this.countSpan = this.shadow.querySelector('span');
// 绑定点击事件
this.button.addEventListener('click', () => {
const count = parseInt(this.countSpan.textContent) + 1;
this.countSpan.textContent = count;
});
}
}
customElements.define('like-button', LikeButton);
</script>
</body>
</html>
保存为 index.html,双击打开,试试点击两个按钮——它们各自独立计数!这就是组件化的魅力。
五、新手常见问题解答(避坑指南)
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 自定义标签不显示 | 忘记调用 customElements.define() |
检查是否注册了类 |
| 样式没生效 | 没用 Shadow DOM,被全局样式覆盖 | 使用 attachShadow 封装 |
| 无法获取子元素 | 在 connectedCallback 前操作 DOM |
把初始化逻辑放在 connectedCallback 中更安全 |
| 组件之间状态共享难 | Web Components 默认无状态管理 | 可结合原生 dispatchEvent 实现通信 |
📌 重要提示:生命周期方法如
connectedCallback(插入 DOM 时触发)比constructor更适合绑定事件或获取属性。
六、学习建议与下一步
Web Components 虽然强大,但不适合构建大型 SPA 应用(缺少状态管理、路由等)。但它非常适合:
- 封装 UI 原子组件(按钮、卡片、弹窗)
- 开发跨框架的微前端模块
- 构建轻量级嵌入式小工具(如评论插件)
推荐学习路径:
- 巩固基础:熟练掌握 Custom Elements + Shadow DOM
- 进阶实践:学习使用
attributeChangedCallback监听属性变化 - 工具辅助:尝试 Lit(Google 出品的轻量库,简化 Web Components 开发)
- 开源参与:在 GitHub 上搜索
web-components,阅读优秀项目源码
🔗 我在 GitHub 上维护了一个入门示例仓库,包含本文所有代码,欢迎 Star:
github.com/yourname/web-components-demo(替换为你的实际链接)
最后,别忘了试试 Aider —— 这是一个新兴的 AI 编程助手,支持直接理解并生成 Web Components 代码。你可以对它说:“帮我写一个带输入框的搜索组件”,它会输出完整的 Custom Element 代码,非常适合初学者快速验证想法。
结语:Web Components 是浏览器给我们的“礼物”,它让我们回归原生,理解组件化的本质。即使你未来主要用 Vue 或 React,掌握它也能让你成为更底层的开发者。希望这篇教程能帮你迈出第一步!
有问题欢迎在评论区留言,我会一一回复。下期我们聊聊如何用 Lit 让 Web Components 开发更高效!

评论 0