
Web Components 是浏览器原生支持的组件化方案。它不依赖任何框架,写出来的组件可以在 Vue、React 甚至纯 HTML 中无缝使用。
## 三个核心技术
- **Custom Elements** — 自定义 HTML 标签 - **Shadow DOM** — 样式隔离,组件内部样式不污染外部 - **HTML Templates** — 可复用的 DOM 片段
## 最小示例:一个倒计时组件
```javascript class CountdownTimer extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); }
connectedCallback() { const seconds = parseInt(this.getAttribute('seconds')) || 60; this.render(seconds); }
render(seconds) { this.shadowRoot.innerHTML = `
${this.formatTime(seconds)}
`; this.startCountdown(seconds); }
formatTime(s) { const m = Math.floor(s / 60); return `${String(m).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`; }
startCountdown(remaining) { this._timer = setInterval(() => { remaining--; const display = this.shadowRoot.querySelector('.timer'); if (display) display.textContent = this.formatTime(remaining); if (remaining <= 0) { clearInterval(this._timer); this.dispatchEvent(new CustomEvent('timeup')); } }, 1000); } disconnectedCallback() { clearInterval(this._timer); } } customElements.define('countdown-timer', CountdownTimer); ``` 只需一行 HTML 就能使用: ```html ```
## Shadow DOM 样式隔离实战
```javascript class UserCard extends HTMLElement { constructor() { super(); const template = document.getElementById('user-card-tpl'); this.attachShadow({ mode: 'open' }) .appendChild(template.content.cloneNode(true)); }
static get observedAttributes() { return ['name', 'avatar', 'role']; }
attributeChangedCallback(name, oldVal, newVal) { const el = this.shadowRoot?.querySelector(`[slot="${name}"]`); if (el) el.textContent = newVal; } } ```
## 何时用 Web Components?
| 场景 | 推荐 | |------|------| | 多个项目共用组件(不同框架) |
最合适 | | 公司内部组件库 |
| | 微前端方案的组件层 |
| | 单一 Vue/React 项目 | 用框架自身的组件即可 | | 需要 SSR | 需要搭配 Lit + SSR |
Web Components 不是要取代 React/Vue,而是在跨框架复用场景下给了你一个原生、无依赖的选择。
---
> 本文由 AI 辅助创作