Web Components技术栈核心组成与浏览器支持
Web Components是W3C标准化的浏览器原生组件方案,由Custom Elements、Shadow DOM、HTML Templates和ES Module Imports四个规范组成。与React/Vue等框架不同,Web Components不依赖任何框架运行时,组件可在任何页面直接使用,天然跨框架复用。Chrome、Firefox、Safari、Edge均已完整支持。
Custom Elements允许注册自定义HTML标签,Shadow DOM提供样式隔离与DOM封装,HTML Templates定义可克隆的DOM模板。三者的组合使得组件具有独立作用域、样式不泄漏、DOM结构不暴露的特性。
Custom Elements注册与生命周期回调实战
Custom Elements通过customElements.define()注册,支持autonomous(独立标签)和customized built-in(扩展原生标签)两种模式。生命周期回调包括connectedCallback、disconnectedCallback、adoptedCallback和attributeChangedCallback。
class StarRating extends HTMLElement {
static get observedAttributes() {
return ['value', 'max', 'readonly'];
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this._value = 0;
this._max = 5;
this._readonly = false;
}
connectedCallback() {
this._value = Number(this.getAttribute('value')) || 0;
this._max = Number(this.getAttribute('max')) || 5;
this._readonly = this.hasAttribute('readonly');
this.render();
}
attributeChangedCallback(name, oldVal, newVal) {
if (oldVal === newVal) return;
switch(name) {
case 'value': this._value = Number(newVal) || 0; break;
case 'max': this._max = Number(newVal) || 5; break;
case 'readonly': this._readonly = newVal !== null; break;
}
if (this.shadowRoot) this.render();
}
render() {
const stars = Array.from({length: this._max}, (_, i) => {
const filled = i < this._value;
return '<span class="star ' + (filled ? 'filled' : '') +
'" data-index="' + i + '">' + (filled ? '\u2605' : '\u2606') + '</span>';
}).join('');
this.shadowRoot.innerHTML = `
<style>
:host { display: inline-flex; gap: 2px; cursor: pointer; }
.star { font-size: 24px; color: #ccc; transition: color 0.2s; }
.star.filled { color: #f5a623; }
.star:hover { color: #f5a623; }
</style>
${stars}
`;
if (!this._readonly) {
this.shadowRoot.querySelectorAll('.star').forEach(star => {
star.addEventListener('click', () => {
this._value = Number(star.dataset.index) + 1;
this.setAttribute('value', this._value);
this.dispatchEvent(new CustomEvent('change', {
detail: { value: this._value },
bubbles: true
}));
});
});
}
}
}
customElements.define('star-rating', StarRating);
Shadow DOM样式隔离与CSS自定义属性穿透
Shadow DOM的核心价值是样式隔离:组件内部CSS不会影响外部,外部样式也不会穿透进组件。但CSS自定义属性(Custom Properties)天然穿透Shadow DOM边界,这是组件主题化的关键机制。
class ThemeButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
:host {
--btn-bg: var(--theme-primary, #1a73e8);
--btn-color: var(--theme-on-primary, #fff);
--btn-radius: var(--theme-radius, 6px);
--btn-padding: var(--theme-padding, 8px 20px);
display: inline-block;
}
button {
background: var(--btn-bg);
color: var(--btn-color);
border: none;
border-radius: var(--btn-radius);
padding: var(--btn-padding);
font-size: 14px;
cursor: pointer;
transition: opacity 0.2s;
}
button:hover { opacity: 0.85; }
button:active { opacity: 0.7; }
</style>
<button><slot></slot></button>
`;
}
}
customElements.define('theme-button', ThemeButton);
Web Components与React/Vue框架集成方案
Web Components可直接在React和Vue项目中使用。React 18+对Web Components的支持已大幅改善,Vue 3通过v-is指令或直接注册原生元素即可使用。
// React中使用Web Components
function App() {
const ratingRef = useRef();
useEffect(() => {
const handler = (e) => {
console.log('评分变更:', e.detail.value);
};
ratingRef.current?.addEventListener('change', handler);
return () => ratingRef.current?.removeEventListener('change', handler);
}, []);
return (
<div>
<star-rating ref={ratingRef} value={3} max={5}></star-rating>
<theme-button>确认</theme-button>
</div>
);
}
// Vue 3中使用Web Components
// main.js:
// app.config.compilerOptions.isCustomElement = tag => tag.includes('-')
Web Components不替代框架而是互补:用Web Components封装跨项目复用的基础UI组件(按钮、输入框、弹窗),框架继续负责应用状态管理、路由和业务逻辑。这种分层策略在企业微前端架构中尤其有效,各子应用可独立使用不同框架,共享组件层通过Web Components统一。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/webcomponents-shi-zhan-kai-fa-cong-customelements-dao/