shadow dom 无生命周期钩子,所有钩子来自 custom elements 规范;constructor 中 this.shadowroot 不可用,connectedcallback 才确保其就绪;observedattributes 必须显式声明,attributechangedcallback 参数中 newvalue 恒为字符串;disconnectedcallback 需手动清理外部引用以防内存泄漏;open/closed 模式不影响钩子执行。

Shadow DOM 本身不提供生命周期钩子;所有标准生命周期回调(如 connectedCallback)都来自 Custom Elements 规范,与 Shadow DOM 的 mode(open 或 closed)完全无关。
为什么 connectedCallback 能访问 this.shadowRoot,但 constructor 不能
因为 constructor 在元素实例化时立即执行,此时它尚未插入 DOM,this.shadowRoot 还未创建(即使你已在 constructor 中调用 this.attachShadow({ mode: 'open' }),也必须等浏览器完成初始化流程后才真正可用)。而 connectedCallback 的触发前提是元素已被插入文档——这时 Shadow Root 已就绪,DOM 可安全操作。
- ✅ 正确:在
connectedCallback中调用this.shadowRoot.querySelector('button')或fetch() - ❌ 错误:在
constructor中写this.shadowRoot.innerHTML = '<slot></slot>'—— 会报Cannot read property 'innerHTML' of null - ⚠️ 注意:
attachShadow必须在constructor或connectedCallback中调用,但仅调用不等于“已就绪”;只有connectedCallback才是 DOM 可用的确定信号
attributeChangedCallback 不生效?检查 observedAttributes 和参数类型
attributeChangedCallback 是被动触发的钩子,浏览器不会自动监听任意属性——你必须显式声明哪些属性需要被观察,且传入值始终是字符串。
- ✅ 必须定义静态 getter:
static get observedAttributes() { return ['disabled', 'count']; } - ✅ 参数顺序固定:
attributeChangedCallback(attrName, oldValue, newValue),其中oldValue首次为null,不是undefined - ⚠️ 常见错误:把
count="42"当作数字用,实际newValue是字符串"42",需手动转类型:Number(newValue)或JSON.parse(newValue) - ? 提示:若属性初始值来自 HTML(如
<my-el count="5"></my-el>),connectedCallback中应主动调用一次this.attributeChangedCallback('count', null, this.getAttribute('count'))来同步状态
disconnectedCallback 是防内存泄漏的最后防线
这个钩子常被跳过,但它直接决定组件是否真能被 GC 回收。Shadow DOM 内部的事件监听、定时器、MutationObserver 若未清理,会持续持有对宿主元素的引用,导致整个组件树无法释放。
- ✅ 必须清理:
this._timer && clearTimeout(this._timer)、window.removeEventListener('resize', this._onResize)、this._observer && this._observer.disconnect() - ⚠️ 特别注意:通过
shadowRoot.addEventListener('click', handler)绑定的监听器,**不需要**在disconnectedCallback中移除——Shadow Root 被销毁时会自动清理其内部监听器;但绑定到全局或外部节点的监听器必须手动解绑 - ? 实操建议:在
constructor中初始化this._timer = null等引用,在disconnectedCallback中统一判空清理,避免重复调用出错
最易被忽略的一点:生命周期钩子的执行时机与 Shadow DOM 模式(open/closed)毫无关系——closed 只让 element.shadowRoot 返回 null,但 connectedCallback 照样触发,attributeChangedCallback 照样响应,disconnectedCallback 照样执行。别指望靠 mode: 'closed' 来“控制生命周期”。











