slot仅负责内容投影,不传递状态、不响应变化、不触发重渲染;需通过attribute或CustomEvent显式传入传出状态,并结合observedAttributes与attributeChangedCallback实现响应式控制。

slot 本身不负责状态分发——它只做内容投影,不传递数据、不响应变化、不触发重渲染。想靠写个 <slot></slot> 就让子组件自动同步父组件的 count 或 isExpanded,行不通。
你真正需要的,是把状态通过属性(attribute)或自定义事件(CustomEvent)显式传入/传出,再配合 slot 做结构占位。否则,内容“塞进去了”,但状态还是静止的。
slot 不是响应式通道,别把它当 Vue 的 v-model
常见错误现象:<my-modal open="true"><p slot="content">加载中...</p></my-modal> 里,后续 JS 改了 element.open = false,但弹窗没关闭,<p></p> 也没消失——因为 <slot></slot> 不监听属性变更,也不订阅数据变化。
-
slot分发的是 DOM 节点引用,不是响应式代理;节点挂载后,外部改数据不会触发 slot 重投递 - 如果你在 slot 里写了
{{ user.name }}或${this.user.name},那只是初始渲染时的一次求值,后续user变了,它不会更新 - 真要响应式,得靠属性监听(
static get observedAttributes()+attributeChangedCallback)或手动触发 render
用 attribute + slot 组合实现可控的状态驱动
把状态作为 HTML 属性暴露,组件内部监听变更并控制 slot 的可见性或行为。比如:
class MyCard extends HTMLElement {
static get observedAttributes() { return ['disabled']; }
attributeChangedCallback(name, oldVal, newVal) {
if (name === 'disabled') {
this.shadowRoot.querySelector('slot').hidden = newVal !== null;
}
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style> :host([disabled]) { opacity: 0.5; } </style>
<div><slot></slot></div>
`;
}
}
- 外部用
<my-card disabled><button>操作</button></my-card>即可控制 slot 内容是否显示 - 属性变更会触发
attributeChangedCallback,你在这里决定 slot 是否参与渲染(比如加hidden、display: none或切换 fallback - 避免在每次
render()里重建shadowRoot.innerHTML,否则 slot 分发会被打断,已挂载节点丢失
动态内容必须用 template + cloneNode,不能依赖 slot 自动刷新
想让 slot 里显示实时数据(如倒计时、用户头像),不能直接写 <my-card><span>{{ time }}</span></my-card>——浏览器不解析双大括号。得用 JS 动态生成并插入:
立即学习“前端免费学习笔记(深入)”;
- 用
<template>定义结构,document.importNode(tmpl.content, true)克隆后塞进shadowRoot或 slot 容器内 - 监听数据变更(如
MutationObserver或自定义事件),手动更新克隆后的节点文本/属性 - 若用
slot.assignedNodes()拿到内容,注意它返回的是 Light DOM 节点,修改后会实时反映在页面上,但需确保你操作的是正确节点(不是 DocumentFragment)
slotchange 事件只告诉你“谁来了”,不告诉你“怎么变”
slotchange 在 slot 第一次接收到内容或内容节点被增删时触发,但它不提供 diff 信息,也不包含新旧值:
- 适合做初始化逻辑(如给插槽内容加 class、绑定事件),不适合做细粒度状态同步
- 别在
slotchange里反复调用slot.assignedNodes()并做深度比对——性能差,且容易漏掉 text node 变更 - 如果需要监听 slot 内部某个子元素的属性变化,得在那个子元素上单独加
MutationObserver,而不是依赖 slot 本身
slot)和“状态通信”(attribute/CustomEvent/DOM API),混用或误判,就会卡在“内容渲染了,但不动”。



















