customElements.define报DOMException是因为标签名不含短横线、类未继承HTMLElement或注册时机早于DOM就绪;三者任一不满足即直接抛错,非静默失败。

customElements.define 为什么报 DOMException?
注册失败基本就三件事没做对:标签名含短横线、类继承 HTMLElement、注册时机在 DOM 就绪后。浏览器不给商量余地,错一个就直接抛 DOMException,不是静默失败。
-
my-button✅ 合法;mybutton❌ 缺短横线,报Failed to execute 'define' on 'CustomElementRegistry': The name "mybutton" is not a valid custom element name - 类必须写成
class MyButton extends HTMLElement,不能是class MyButton或class MyButton extends Object,否则实例化时触发Illegal constructor - 脚本放在
<head>里且没加defer或DOMContentLoaded监听?HTML 中的<my-button>已被解析为未知节点,后续注册不会自动升级——它永远卡在“未定义”状态
constructor 里能写什么?connectedCallback 又该干啥?
这两个生命周期钩子职责分明,混用就会出问题:DOM 操作失败、属性读不到、Shadow DOM 创建报错。
-
constructor只做三件事:super()、调用this.attachShadow({ mode: 'open' })(如果要用 Shadow DOM)、初始化私有字段(比如this._onClick = this._onClick.bind(this)) -
connectedCallback才是干活的地方:读取this.getAttribute('label')、设置this.shadowRoot.innerHTML、添加事件监听器、发起 fetch 请求(如果需要) - 常见错误:在
constructor里写this.innerHTML = 'xxx'—— 此时元素还没挂载,innerHTML被忽略;或者调this.attachShadow多次,报NotSupportedError: Failed to execute 'attachShadow' on 'HTMLElement'
attributeChangedCallback 怎么同步初始值?
这个回调只响应 DOM 属性的变更,不处理 HTML 中写的初始值。所以 <my-input value="hello"> 的 value 不会进 attributeChangedCallback,得手动补。
- 必须声明
static get observedAttributes() { return ['value', 'disabled']; },否则变更根本不会触发回调 - 首次渲染逻辑仍得放在
connectedCallback里,例如:const value = this.getAttribute('value'); if (value !== null) this._updateInput(value); - 回调里别直接操作外部 DOM 或重复渲染整个 shadowRoot,优先用局部更新(比如只改
input.value),避免性能抖动
Shadow DOM 样式为啥不生效?
Shadow DOM 天然样式隔离,外部 CSS 进不来,内部样式也出不去——不是 bug,是设计。指望全局样式穿透进来,注定失败。
立即学习“前端免费学习笔记(深入)”;
- 样式必须显式注入到
shadowRoot:可以用shadowRoot.innerHTML = '<style>:host { display: block; }</style><div>...',或创建<style>元素 append 进去 - 想让宿主元素响应属性?用
:host([disabled])或:host-context(.dark-theme),但后者兼容性差,慎用 - 不要在 Shadow 内写
<style>body { color: red}</style>——body根本不存在于 shadow tree 中,这条规则等于废纸
最常被忽略的是:attributeChangedCallback 不处理初始值,以及 Shadow DOM 的样式注入必须主动完成——这两点没有 fallback,错了就是白屏或样式丢失,调试时得盯着控制台看是否报错,而不是猜逻辑。



















