Slot 本身不提供配置能力,仅负责内容分发;高度可配置依赖命名插槽、直系子节点约束与 Shadow DOM 封装三者组合,缺一不可。

Slot 本身不提供“配置能力”,它只负责内容分发;真正实现高度可配置,靠的是命名插槽 + 直系子节点约束 + Shadow DOM 封装这三者的组合。没挂 shadowRoot,slot 就是废标签。
为什么写了 slot 却没渲染出内容
这不是语法错误,而是环境缺失。浏览器对 slot 的处理非常“冷酷”:没 Shadow DOM,就直接忽略;有 Shadow DOM 但内容不是直系子节点,就静默丢弃。
- 必须在自定义元素的
constructor或connectedCallback中调用this.attachShadow({ mode: 'open' }),且只能调用一次 -
<my-card><div><h2 slot="title">标题</h2></div></my-card>→<h2>不会被分发,因为它不是<my-card>的直系子节点 - 父级写了
<h2 slot="Title">,但组件内是<slot name="title">→ 大小写不匹配,内容消失,不报错 - 没声明任何
<slot>标签?所有传入内容彻底丢弃,连 fallback 都不会显示
怎么设计具名插槽才能支撑多场景定制
具名插槽不是越多越好,关键在语义清晰、边界明确。一个容器组件通常只需 3–4 个命名插槽,再多反而增加使用者认知负担。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
-
header/footer/main是最安全的命名,符合 HTML5 语义,也便于 CSS::part()或自定义属性透传 - 避免用
left-area、right-panel这类布局导向命名——布局应由使用者通过 CSS 控制,组件只暴露语义区域 - 多个同名
<slot name="item">?只有第一个生效,其余空着;想支持列表项,应该用单个<slot name="items">让使用者传整个<ul> - 默认插槽(无
name)只能有一个,且应作为兜底内容区,比如<slot>暂无内容</slot>
如何监听插槽内容变化并响应式更新 UI
slotchange 事件不是“内容一变就触发”,它只在浏览器完成一次完整的内容分发后触发,且不冒泡。想拿到真实节点,必须绑定到具体 <slot> 元素上。
立即学习“前端免费学习笔记(深入)”;
- 不要在
connectedCallback里立刻查slot.assignedNodes()—— 此时返回空数组是常态 - 正确写法:
const titleSlot = this.shadowRoot.querySelector('slot[name="header"]'); titleSlot.addEventListener('slotchange', () => { const nodes = titleSlot.assignedNodes({ flatten: true }); /* 处理 nodes */ }); -
{ flatten: true }必须加,否则嵌套在<template>或<slot>fallback 里的节点不会被展开 - Firefox 63 以下不支持
slotchange,需降级用MutationObserver监听slot的childList
最易被忽略的点:slot 分发发生在浏览器渲染管线中,它不触发 Vue 或 React 的响应式更新,也不参与原生 Custom Element 的 attributeChangedCallback。你得自己管好节点生命周期——比如清空旧内容、避免重复绑定事件、处理文本节点与元素节点的差异。


















