HTML5 customElements.define()注册自定义元素须继承HTMLElement、名称含短横线;HTML4不支持自定义标签语义,仅作未知元素处理;主流浏览器兼容但有细节差异;相比div+class,custom element提供语义化、封装性与原生生命周期。
customElements.define() 怎么注册一个自定义元素必须继承 HTMLElement 或其子类,不能直接用空对象;注册名必须包含短横线(-),比如 my-button 合法,mybutton 会报错。
常见写法:
class MyButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = ``;
}
}
customElements.define('my-button', MyButton);
注意点:
constructor 中必须先调 super(),否则报 Failed to construct 'HTMLElement': Please use the 'new' operator
connectedCallback 里反复调 this.attachShadow(),否则重复挂载会失败document.createElement('my-button') 创建,需确保 define 已执行(脚本顺序或放在 里)不能。HTML4 没有规范支持自定义标签语义,浏览器遇到未知标签会:
HTMLUnknownElement(不是 HTMLElement 子类)connectedCallback 等全无效)my-tag { display: block } 可能生效,但无法绑定行为、无法封装逻辑即使强行用 document.createElement('my-tag') 在 IE8+ 注册,也只是让标签“存在”,仍无自定义能力——这和 HTML5 的 cust 完全不同。
omElements
主流浏览器都支持,但细节有坑:
customElements.define() 的第三个参数({ extends: 'button' })shadowRoot 和 ,旧版需手动 fallbackis="xxx" 语法(如 ),需显式传 { extends: 'button' },且仅适用于内置标签扩展检查是否可用:
if ('customElements' in window) {
// 安全使用
}
div + class 模拟,非要用 custom element核心区别在封装边界和语义表达:
是声明式语义,而 是弱耦合的约定,无法被辅助工具、框架或未来标准识别
- custom element 自动获得
attributeChangedCallback,属性变更可响应;普通 div 需手动监听 MutationObserver
- shadow DOM 天然隔离样式和事件冒泡,避免全局污染;class 方案要靠 BEM、CSS-in-JS 等额外机制模拟
- 框架(如 Lit、Stencil)底层仍基于
customElements.define(),绕不开这个原生机制
真正难的不是注册一个标签,而是设计好属性/事件/插槽契约,以及处理好 SSR、无障碍、焦点管理这些隐性需求。