connectedCallback仅在元素首次真正插入document主树时触发,HTML中声明但未定义、动态创建后未appendChild、innerHTML插入或Shadow DOM内插入均不触发;attributeChangedCallback需通过static get observedAttributes()显式声明监听属性名,且仅响应attribute变更;disconnectedCallback是清理定时器、请求和事件监听的最后时机,但不保证一定执行。

connectedCallback 只在元素首次挂载到主 DOM 树时触发,不是写了标签就执行,也不是每次 appendChild() 都调用;错过注册时机或没真正挂载,它就永远不会来。
为什么 connectedCallback 没执行?
它只响应“首次真正插入 document 主树”这一事件,和 HTML 是否写在那里、JS 是否定义了类,是两回事。
- HTML 里写了
<ds-button></ds-button>,但customElements.define()还没运行 → 浏览器当HTMLUnknownElement处理,静默忽略,不触发任何回调 - 动态创建后没
appendChild():const el = document.createElement('ds-button')后直接丢弃 → 不挂载,不触发 - 用
innerHTML = '<ds-button></ds-button>'插入 → 字符串解析绕过生命周期钩子,connectedCallback完全不进 - Shadow DOM 内部插入该元素 → 不触发父文档的
connectedCallback,它只认当前文档主树
attributeChangedCallback 怎么监听才生效?
它不是自动监听器,必须靠 observedAttributes 显式声明,且只响应 attribute 级变更(不是 property),连大小写、连字符错一个都不行。
-
static get observedAttributes()必须返回字符串数组,例如return ['data-id', 'disabled'];写成['DataId']或漏掉'data-id'就静默失效 - HTML 中写
<ds-input data-id="123"></ds-input>,JS 里就得监听'data-id',不能简写为'id'或驼峰'dataId' -
this.setAttribute('data-id', '456')会触发;但this.dataset.id = '456'或this['data-id'] = '456'不会 - 首次渲染的属性值不会进这个回调(
oldValue是null),初始化逻辑仍得在connectedCallback里手动读this.getAttribute('data-id')
disconnectedCallback 能放心做清理吗?
它是你清理定时器、取消请求、移除事件监听的最后确定时机,但浏览器不保证它一定执行——页面刷新、关闭 tab、进程崩溃时可能直接跳过。
立即学习“前端免费学习笔记(深入)”;
- 所有
setTimeout/setInterval必须在这里clearTimeout()/clearInterval(),但也要加 fallback:比如用AbortController.signal控制fetch,即使回调没跑完也能中断 - 不要在这里操作 DOM(如
this.remove()),此时元素已脱离主树,部分引用可能失效 - 避免依赖它做关键数据持久化(比如写
localStorage),应提前存或双保险处理 - 清理逻辑建议加 guard 判断(如
if (this._timer) { clearTimeout(this._timer); this._timer = null; }),因为同一元素不会多次触发该回调,但代码可能被重复调用
最常被忽略的其实是时序问题:自定义元素不是“写完就活”,而是浏览器在 DOM 构建完成后的某个精确节点上才开始调度回调;一旦注册晚了、挂载方式不对、或混淆 attribute/property,整个生命周期就断在第一环,后面再怎么写逻辑都白搭。



















