Web Components 是浏览器原生组件化方案,含 Custom Elements、Shadow DOM 和 HTML Templates;Custom Elements 需继承 HTMLElement、类名含短横线、用 define() 注册;关键钩子为 connectedCallback 和 attributeChangedCallback;Shadow DOM 提供样式与脚本隔离。
它由三部分组成:Custom Elements(自定义元素)、Shadow DOM(影子 DOM)、HTML Templates( 和 )。其中最常用、最易上手的是 Custom Elements —— 它让你用 JS 注册一个带行为的 HTML 标签,比如 ,浏览器会识别并实例化它。
customElements.define() 创建自定义元素,必须继承 HTMLElement
不能直接传入普通函数或对象,必须是类(或构造函数),且必须 extends HTMLElement。否则会报错:Failed to execute 'define' on 'CustomElementRegistry': Class constructor X cannot be invoked without 'new'。
-),如 MyButton ❌,my-button ✅div、button)define() 后才 class MyEl extends HTMLElement { ... })class CounterButton extends HTMLElement {
constructor() {
super();
this.count = 0;
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
`;
}
connectedCallback() {
this.shadowRoot.querySelector('button').addEventListener('click', () => {
this.count++;
this.shadowRoot.querySelector('button').textContent =
`${this.getAttribute('label') || 'Click me'} (${this.count})`;
});
}
}
customElements.define('counter-b
utton', CounterButton);
connectedCallback 和 attributeChangedCallback 是关键生命周期钩子它们不是可选的“增强功能”,而是处理真实交互和响应属性变化的核心入口。漏掉 connectedCallback,DOM 插入后逻辑不会自动触发;不监听 observedAttributes 并实现 attributeChangedCallback,就无法响应 setAttribute() 或属性绑定变更。
connectedCallback:元素被插入文档时触发(可多次),适合绑定事件、发起请求、初始化 Shadow DOMdisconnectedCallback:从文档移除时触发,适合清理定时器、事件监听器observedAttributes 数组,并在 attributeChangedCallback(name, oldVal, newVal) 中处理string 类型属性生效;布尔/数字/对象需手动转换(例如用 this.hasAttribute('disabled') 判断布尔值)这是优点也是约束点:你在 shadowRoot.innerHTML 里写的 不会影响外部,外部 CSS 也默认进不了 Shadow DOM(除非用 ::part() 或 :host 显式穿透)。但这也意味着:
注入样式到 Shadow DOM 内部(得用 fetch + innerHTML 或 adoptedStyleSheets)(会被忽略) 是内容分发出口,但仅能分发 Light DOM 的子节点,不能跨 Shadow 边界“穿透”渲染如果需要复用样式,推荐用 CSSStyleSheet 实例配合 adoptedStyleSheets,而不是拼接字符串 —— 更安全、支持 HMR、避免重复解析。