仅在shadow dom中生效,需同时满足自定义元素注册、调用attachshadow()、位于shadowroot下三个条件;light dom中为普通标签,无内容分发功能。

template 标签本身不渲染,也不解析 slot
直接写 <template><slot></slot></template> 不会触发任何内容分发,浏览器只把它当一段未激活的 HTML 字符串。它既不参与 DOM 渲染,也不扫描内部 <slot></slot> 标签——因为 <slot></slot> 在 Light DOM 中就是普通标签,没意义。
常见错误现象:
- 把
<template></template>当成“可插入组件”,直接innerHTML += template.outerHTML→ 内容静默丢弃 - 在普通 div 里写
<slot name="header"></slot>→ 完全无效,控制台无报错 - 期望
<template id="card"><div><slot></slot></div></template>能自动绑定父级传入内容 → 实际只是存了一段结构,没桥接逻辑
slot 必须出现在 Shadow DOM 内,且依赖自定义元素注册
<slot></slot> 只在 Shadow DOM 环境中起作用,且必须满足三个硬性条件同时成立:自定义元素已注册、attachShadow({ mode: 'open' }) 已调用、<slot></slot> 出现在 shadowRoot 下(比如克隆自 <template></template> 的 content)。
实操建议:
- 先定义模板:
<template id="card-tpl"><div class="card"> <header><slot name="header">Default</slot></header><main><slot>Content</slot></main> </div></template> - 再写类:
class MyCard extends HTMLElement { constructor() { super(); const tpl = document.getElementById('card-tpl'); this.attachShadow({ mode: 'open' }).appendChild(tpl.content.cloneNode(true)); } } - 最后注册:
customElements.define('my-card', MyCard) - 使用时必须是直系子节点:
<my-card><h2 slot="header">Title</h2> <p>Body</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/shouce/1862" title="使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件"><img src="https://img.php.cn/upload/manual/000/000/010/170901721079108.gif" alt="使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/shouce/1862" title="使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件" class="overflowclass">使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件</a> <p class="overflowclass">如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Andr​​oid友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Andr​​oid应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更</p> </div> <a rel="nofollow" href="/xiazai/shouce/1862" title="使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div></my-card>✅;<my-card><div><h2 slot="header">Title</h2></div></my-card>❌(<div> 隔断了投射链) <h3>::slotted() 不是全局样式穿透,只匹配直系子节点</h3> <p><code>::slotted()是单向样式通道,不是“让插槽内容继承父样式”的快捷方式。它只对被投射进来的**直系子元素**生效,且不支持嵌套选择器或伪类。容易踩的坑:
-
::slotted(p) { color: red; }✅ 有效;::slotted(.header h2)❌ 完全无效 -
::slotted(p::first-line)❌ 不支持伪类 - Light DOM 中的全局样式(如
p { font-size: 14px; })仍会命中插槽内容 ——::slotted()不是隔离开关,只是显式声明的透传入口 - 想控制更深层结构?得把那部分也封装成带 Shadow DOM 的自定义元素,而不是靠加一层选择器
验证 slot 是否真有内容进来,别靠肉眼
渲染结果不可信,换行符、空格都会变成文本节点,导致 fallback 显示异常。调试时优先用 API 查实时状态:
-
this.shadowRoot.querySelector('slot[name="header"]').assignedNodes()→ 返回空数组说明没内容进来 -
assignedNodes({ flatten: true })可展开默认插槽的嵌套文本节点,但注意:哪怕只有一个换行符,也算一个Text节点 -
assignedElements()自动过滤纯文本节点,更适合判断“有没有实际元素被塞进来” -
slotchange事件只在动态增删子节点时触发,首次挂载不 fire,别指望它初始化就回调
真正难的不是写对语法,而是接受 Shadow DOM 的投影本质:内容始终留在 Light DOM,
<slot></slot>只是窗口,不是搬运工;没调attachShadow(),所有 slot 和样式隔离逻辑都退化为无意义的字符串。 -










