innerhtml或insertadjacenthtml注入的html不会触发custom elements的connectedcallback,也不会执行script标签;必须手动调用customelements.upgrade()才能触发生命周期。

直接说结论:innerHTML 或 insertAdjacentHTML 注入的 HTML 片段,**不会触发 Custom Elements 的 connectedCallback,也不会自动执行其中的 <script></script> 标签**——除非你手动干预。
为什么 injected HTML 不触发 connectedCallback
Custom Elements 的生命周期回调(如 connectedCallback)只对“被浏览器解析器创建并挂载”的元素生效。而通过 el.innerHTML = '...' 或 el.insertAdjacentHTML('beforeend', '<my-widget></my-widget>') 注入的内容,是字符串解析后由 DOM API 创建的节点,绕过了浏览器的 HTML 解析流程。
这意味着:
-
<my-widget></my-widget>被当作普通标签插入,不会被升级(upgrade),connectedCallback永远不调用 - 即使该自定义元素已注册,也必须显式调用
customElements.upgrade(el)才能触发初始化 - 如果注入的是未注册的标签名,后续注册也无效;必须先注册,再注入,再 upgrade
如何让 injected 元素正确触发生命周期
关键动作是:注入后,对新插入的节点及其子树调用 customElements.upgrade()。
示例:
const container = document.getElementById('app');
container.innerHTML = '<my-card data-id="123"></my-card>';
// ✅ 必须手动 upgrade
customElements.upgrade(container); // 升级 container 下所有待升级元素
// 或更精确地:
const newEl = container.querySelector('my-card');
if (newEl) customElements.upgrade(newEl);
注意点:
-
customElements.upgrade()是幂等的,重复调用无副作用 - 它只对“已注册但尚未升级”的元素生效;对原生元素或已升级过的元素无操作
- 如果注入的是深层嵌套结构(比如含多个自定义元素),推荐传入父容器而非逐个查取
- 不要在
constructor里调用this.attachShadow后再依赖connectedCallback做 DOM 操作——因为 upgrade 后会立即走完整生命周期,但此时 shadowRoot 已存在
script 标签在 innerHTML 中为何不执行
这是规范行为:innerHTML = '...<script>console.log(1)</script>...' 中的 <script></script> **会被解析为文本节点,不会执行**。
原因:
- DOM API(如
innerHTML、insertAdjacentHTML)不触发脚本执行,这是安全机制 - 只有浏览器 HTML 解析器在初始页面加载或
document.write(已废弃)时才会执行内联脚本 - 动态创建
<script></script>节点并 append 到 DOM,才可执行(但需注意 CSP 限制)
若真需执行逻辑,应改用:
const script = document.createElement('script');
script.textContent = 'console.log("injected logic");';
container.appendChild(script);
容易忽略的兼容性与性能陷阱
在 fragment 注入场景下,最容易被跳过的不是语法,而是时机和范围判断:
- 使用
documentFragment插入时,fragment 本身不触发connectedCallback,只有其子节点被 append 到真实 DOM 后才可能触发——但依然要靠upgrade() - Vue/React 等框架内部会做 patch 和 upgrade 管理,但纯 DOM 场景下没人帮你兜底
- 频繁注入 + upgrade 可能引发微小性能开销,尤其含大量自定义元素时;建议批量操作后统一 upgrade,而非每条插入都调用
- 服务端渲染(SSR)返回的 HTML 若含自定义元素,在 hydrate 阶段必须确保已注册且调用
upgrade(),否则首屏无交互
最常漏掉的一步:忘了检查元素是否已被 upgrade —— el.shadowRoot 为 null 不一定代表没升级,可能是 constructor 里没调 this.attachShadow,也可能是 upgrade 还没发生。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











