customElements.define() 必须在 HTML 解析前同步注册,否则未知标签将永久按 HTMLUnknownElement 处理;attributeChangedCallback 仅响应 observedAttributes 显式声明的 attribute 变更;connectedCallback 仅在首次插入 active DOM 时触发;constructor 中不可操作 DOM;disconnectedCallback 不保证执行,需双重清理。

customElements.define() 必须在元素解析前同步注册
浏览器遇到未知标签(如 <ds-table>)时,会立即按 HTMLUnknownElement 处理,后续无论 JS 是否加载、是否调用 customElements.define(),该节点都永远失去自定义行为。这不是延迟问题,而是不可逆的解析判定。
- 常见错误:Vite 动态导入中注册 —— 首次访问时组件 DOM 已存在,但类还没定义,
connectedCallback永远不执行 - 正确做法:所有
customElements.define()收口到一个顶层同步模块(如components/index.js),并通过<script defer>或 ESM 模块顶层导入确保执行早于 HTML 解析 - SSR 场景下必须加守卫:
if (typeof window !== 'undefined') { customElements.define(...) },否则 Node.js 环境直接报错 - 构建工具要防拆包:Webpack 中需配置
module.rules.exclude = /node_modules/,避免自定义元素类被误打进import()异步 chunk
attributeChangedCallback 不触发?先查 observedAttributes 声明
attributeChangedCallback 不是监听器,它只响应 observedAttributes 显式列出的 attribute 名称变更,且仅对 attribute 级操作(setAttribute 或 HTML 初始属性)生效,property 赋值(如 el.value = 'x')完全不触发。
- 静态 getter 必须返回字符串数组:
static get observedAttributes() { return ['data-id', 'disabled']; },写成['DataId']或漏掉连字符都会失效 - HTML 写
<ds-input data-user-id="123">,就必须监听'data-user-id',不是'userId'或'user-id' - 首次渲染的属性值不会进这个回调(
oldValue是null),初始化逻辑仍得在connectedCallback里手动读取:this.getAttribute('data-id') - property 和 attribute 同步需手动维护:在 setter 里调用
this.setAttribute('data-id', val)
connectedCallback 只触发一次,但“挂载”有严格定义
connectedCallback 仅在元素**首次真正插入 active DOM 树**时运行,不是标签一写就调,也不是 document.createElement() 就触发。它不响应重复 appendChild(),也不在 Shadow DOM 内部插入时触发父级回调。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 动态创建后没挂载:
const el = document.createElement('ds-card'); // 不触发,必须紧接parent.appendChild(el) - 框架(如 React、Vue)动态插入可能绕过原生生命周期 —— 它们常走 innerHTML 或虚拟 DOM diff,不走标准
appendChild路径 - 滚动列表或大屏复用场景下,元素可能被移出又重插,但
connectedCallback不再执行,此时需自行维护状态池或用 MutationObserver 监听子树变化 - constructor 中禁止操作 DOM:
this.shadowRoot为null,querySelector查不到自己,只能做轻量初始化(如声明私有变量、绑定方法)
disconnectedCallback 不可靠,清理必须双保险
disconnectedCallback 是你释放定时器、取消请求、解绑事件的最后机会,但它不保证执行 —— 页面刷新、关闭 tab、后台进程销毁时,浏览器可能直接回收上下文。
立即学习“前端免费学习笔记(深入)”;
- 所有
setTimeout/setInterval必须在这里清除,但也要 fallback:用AbortController.signal控制 fetch,即使回调未执行也能中断请求 - 全局事件监听(如
window.addEventListener('resize', ...))必须配对移除,且建议加 guard 判断(如if (this._resizeHandler)),避免重复调用出错 - 不要在其中做关键数据持久化(如写 localStorage),应提前保存或使用 beforeunload 等更可靠的时机
- Shadow DOM 内部创建的
MutationObserver或ResizeObserver也必须在此显式.disconnect(),否则内存泄漏风险极高
adoptedCallback,display: contents 祖先让 hidden 失效,这些细节一旦忽略,调试成本会陡增。


















