不能直接将<template>内容写入shadowRoot.innerHTML,因为innerHTML仅解析字符串、丢失DocumentFragment结构及事件绑定,导致<slot>失效、样式错乱、脚本不执行;必须用document.importNode(template.content, true)克隆后插入。
<template> 内容写进 shadowRoot.innerHTML
因为 shadowRoot.innerHTML 会把字符串当作纯 HTML 解析,而 <template> 的 content 是一个 DocumentFragment,它包含已解析的节点树、保留了事件监听器绑定能力,且天然支持 <slot> 语义。直接 innerHTML 会丢失这些结构信息,导致 slot 不生效、样式作用域错乱、脚本不执行(即使写了也不会自动运行)。
常见错误现象:<slot> 标签原样显示在页面上,或者投射内容完全不出现;shadowRoot.querySelector('slot') 返回 null;自定义元素内部样式被外部覆盖。
document.importNode(template.content, true) 克隆,不能用 template.innerHTML 或 template.outerHTML
querySelector、addEventListener 等方法<style>,它会随 content 一起被克隆并插入 Shadow DOM,实现样式局部化attachShadow() 后立刻用 importNode() 插入模板的典型顺序顺序错了就白忙:Shadow DOM 创建和模板激活必须严格串行,且不能跳过克隆步骤。
element.attachShadow({ mode: 'open' }),拿到 shadowRoot
<template id="xxx"> 元素,读取其 .content
document.importNode(template.content, true) 深度克隆 —— 第二个参数 true 必须传,否则子节点不复制shadowRoot.appendChild(clone)
constructor 里操作 DOM,应在 connectedCallback 中执行,确保宿主已挂载<slot> 如何与 Shadow DOM 的投影机制配合<slot> 不是占位符标签,而是内容出口控制器。它只在 Shadow DOM 上下文中才有意义;放在 light DOM 里毫无作用。
立即学习“前端免费学习笔记(深入)”;
<slot name="header"></slot>,宿主元素内对应要写 <span slot="header">标题</span>
slot 名称时,内容会被丢弃(不是隐藏);可用 <slot></slot> 作为默认出口slotchange 事件才能感知投射内容更新,slot.assignedNodes({ flatten: true }) 才能拿到真实节点::slotted(*) 只能设置简单继承属性(如 color、font-size),不能设 display 或 margin —— 这些需由投射内容自身控制看似简单的组合,在实际项目里最容易栽在边界条件上。
<template> 在所有现代浏览器中支持良好,但 IE 完全不支持,需 polyfill(如 template-polyfill)<template> 当普通标签渲染,导致服务端生成无意义的空标签shadowRoot 显示为空,大概率是 attachShadow 调用失败或重复调用<script> 不会自动执行 —— 即使克隆进 Shadow DOM 也不行,必须手动创建新 script 节点并设置 textContent 后插入importNode 这一步,或者误以为 <slot> 能跨 Shadow DOM 边界自动“拉”内容。它只响应宿主元素子节点的 slot 属性,不爬取 DOM 树,也不触发重排。