Web Components 实战指南
六月 23, 2026
web-development web-components javascript frontend-development custom-elements shadow-dom
# Web Components 实战:给现代 Web 开发者的指南
圈内有个老梗:每隔几年就有人"发明"一套组件系统,大伙儿兴奋一把,然后被坑,然后又兴奋。
但 Web Components 还真不是一阵风——它是浏览器自带的能力,专门解决封装、复用和跨框架协作的问题。跟你 2019 年追的那个框架不一样(就不点名了),等那框架凉透了,Web Components 还能继续跑。
今天聊点实在的:怎么写出能上生产的 Web Components,而不是玩具 Demo。
## Custom Element 长什么样
说白了,Custom Element 就是继承自 `HTMLElement` 的 JavaScript 类。就这么简单。
真正有意思的是那几个生命周期钩子——它们决定了你这个组件什么时候"出生"、什么时候"登场"、什么时候"离开"。
```javascript
class MyButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
// 组件被挂到页面上啦
this.render();
}
disconnectedCallback() {
// 清理工作放这儿
}
attributeChangedCallback(name, oldValue, newValue) {
// 监听属性变化
}
}
```
`connectedCallback` 就是组件的"你好世界"——DOM 初始化、绑定事件、让组件活起来,都在这步。`disconnectedCallback` 同样重要:该删的监听器要删掉,不然小心内存泄漏。
## Shadow DOM:组件的私人领地
重头戏来了。
Shadow DOM 会在组件内部创建一个独立封装的 DOM 树。对外不可见,内部定义的样式不会污染外面,外面的样式也别想渗透进来(除非你主动开门)。
你可以把它想象成组件住在自己的小宇宙里。
```javascript
class FancyCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.shadowRoot.innerHTML = `
`;
}
}
```
`:host` 伪类就是组件本身的根元素——用来给整个组件 wrapper 写样式,或者根据属性切换状态。
## Slots:组件之间的任意门
Slots 就是桥,接通 Shadow DOM 和外面的世界。
用命名的 slot 可以精准投放内容:
```html
我的卡片标题
```
```javascript
// 组件内部
const slot = this.shadowRoot.querySelector('slot[name="title"]');
slot.addEventListener('slotchange', () => {
const assignedNodes = slot.assignedNodes();
// slot 内容变了,做点反应
});
```
Slots 实现了"灵活"和"封装"两手抓——这在 Web 开发里可不多见。
## 好用的组件设计套路
### 输入和输出
组件跟外部世界交流,靠的是清晰接口:
- **Attributes**:HTML 属性传配置(``)
- **Properties**:JS 代码直接改(`element.theme = 'dark'`)
- **Events**:往外发通知(`element.addEventListener('change', handler)`)
- **Methods**:暴露 API(`element.reset()`)
所有组件统一这套规则。以后维护代码,你会感谢自己。
### CSS 变量:换肤不要太轻松
别把颜色间距写死,用 CSS 变量来管理主题:
```css
:host {
--button-bg: #007bff;
--button-text: white;
--button-padding: 0.75rem 1.5rem;
--button-radius: 4px;
}
button {
background: var(--button-bg);
color: var(--button-text);
padding: var(--button-padding);
border-radius: var(--button-radius);
}
```
用户想换主题?一行 CSS 搞定:
```css
my-button {
--button-bg: #28a745;
}
```
## 什么时候用、什么时候别用
Web Components 擅长的场景:
- **设计系统**:打造全站统一的 UI 库,跑到哪儿都正常
- **跨框架项目**:React、Vue、原生 JS 都能用同一套组件
- **长期项目**:写完不用隔两年大重构
但不是万能药:
- **状态复杂的界面**:React 那一套生态还是更成熟
- **简单的静态内容**:一个没什么交互的 `` 用 Web Components 就杀鸡用牛刀了
## 做出能经得住时间的组件
Web Components 标准已经相当成熟了。浏览器支持也到位。Google 团队出的 Lit 工具链让开发体验好了很多,同时输出的还是标准化的 Custom Element。
关键认知:**Web Components 不是来跟 React、Vue 抢饭碗的**,是互补关系。跨框架的底层组件用 Web Components,应用逻辑交给趁手的框架。
浏览器平台的能力,其实经常被我们低估。下次想引入一个依赖来解决 UI 问题之前,先问问自己:浏览器本身能不能干这事?
你的打包体积(以及未来的维护者)会感谢你的。
---
*想部署下一个 Web 项目?[NameOcean 的 Vibe Hosting](https://www.nameocean.net/vibe-hosting) 为现代 Web 应用提供坚实基础,AI 驱动的工具完美适配你的开发流程。*
这段放进默认 slot 里。