- 开发工具
- 前端
- 前端构建
【免费下载链接】stencil
A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, (+ more) and traditional web applications from a single, framework-agnostic codebase.
导读
本文以 Stencil 仓库 test/end-to-end 端到端测试套件中的 slot-parent-cmp 组件为实例,系统讲解 Stencil 组件中slot(插槽)的声明方式、嵌套转发机制、默认插槽的透传,以及docs-readme输出目标如何自动生成组件 API 文档与依赖关系图。读完本文,你将掌握 Stencil 中「组件声明<slot />→ 上层组件转发子内容 → Shadow DOM 渲染 → e2e 断言验证」的完整链路,并能读懂仓库中任意组件自动生成的readme.md。
说明:
test/end-to-end/src/slot-parent-cmp/readme.md是 Stencil 通过docs-readme输出目标自动生成的组件文档,属于"组件 API 快照",其信息完全来源于组件源码元数据,因此本文以该自动文档为骨架,结合源码、运行时实现与 e2e 测试展开解读。
一、自动生成的组件文档:readme.md 里有什么
slot-parent-cmp的 readme.md 由编译器自动生成,包含四个固定小节:Properties(属性)、Slots(插槽)、Dependencies(依赖关系)、以及依赖图(Mermaid)。这类文档的生成逻辑位于 src/compiler/docs/readme 目录,例如 markdown-slots.ts 会把组件元数据中的插槽信息渲染成## Slots表格:
- 表头固定为
Slot | Description; - 默认插槽(
name为空字符串)在表格中表现为空白的 Slot 单元格; - 具名插槽则会以
`"name"`的形式输出。
也就是说,本文档中 "The default slot" 这一行,正是编译器从 slot-parent-cmp.tsx 源码中提取出的插槽声明生成的。readme.md第一行的# slot-parent-cmp标题也来自组件tag。
Properties:组件公开属性一览
文档的 Properties 表格如下:
| Property | Attribute | Description | Type | Default |
|---|---|---|---|---|
label | label | string | undefined |
这对应源码中的一行声明:
@Prop() label: string;Property与Attribute同列展示说明该 Prop 未显式配置attribute别名,因此默认使用与属性同名的 HTML 属性label。类型string与默认值undefined均来自 Stencil 的静态类型分析。该属性在渲染中被直接输出到组件根节点:
render() { return ( <Host> {this.label} ... </Host> ); }即当使用者写入<slot-parent-cmp label="One" />时,组件根元素内会渲染出文本节点One,随后才是插槽内容。这为下文要讲的插槽顺序问题埋下了伏笔。
二、组件源码:一次完整的"插槽转发"示例
slot-parent-cmp.tsx 的全部实现只有十几行,但完整演示了 Stencil 插槽的核心用法:
import { Component, Host, Prop, h } from '@stencil/core'; @Component({ tag: 'slot-parent-cmp', }) export class SlotParentCmp { @Prop() label: string; render() { return ( <Host> {this.label} <slot-cmp> <slot /> </slot-cmp> </Host> ); } }要点拆解:
<slot />声明默认插槽:在 JSX 中直接书写<slot />,表示该组件接收并渲染父级传入的子内容(light DOM)。由于未指定name,它接收的是"默认插槽"内容。- 插槽转发(slot forwarding):
<slot />被包裹在<slot-cmp>内部,也就是说slot-parent-cmp把"接收到的子内容"作为slot-cmp的默认插槽内容继续向下传递。这就是文档 Dependencies 中slot-parent-cmp --> slot-cmp这条边对应的运行时行为。 Host根节点承载文本:{this.label}渲染在Host内、<slot-cmp>之前,是插槽之外的内容。
这一"插槽再插槽"的嵌套结构正是仓库中 nested-slot-forwarding.spec.tsx 所覆盖的运行时场景——Stencil 的虚拟 DOM 渲染器会把最内层<slot />的内容投影到最终落点,而不是在中间组件处"卡住"。
三、上下游组件:插槽在真实使用中的位置
3.1 上游:slot-cmp-container如何投喂插槽内容
slot-parent-cmp的唯一使用者是 slot-cmp-container,后者是一个shadow: true的 Shadow DOM 组件,渲染结构如下:
<Host> <slot-cmp> <slot-parent-cmp label="One" /> </slot-cmp> <slot-cmp> <slot-parent-cmp label="Two" /> </slot-cmp> <slot-cmp> <slot-parent-cmp label="Three" /> </slot-cmp> </Host>这里形成了双层传递:slot-cmp-container把<slot-parent-cmp>元素作为slot-cmp的默认插槽内容;而每个slot-parent-cmp又会把"自身收到的子内容"继续转给它的slot-cmp子组件。componentDidLoad中还会执行一次forceUpdate(this.host),用于验证强制刷新后插槽投影依然保持正确顺序。
3.2 下游:slot-cmp是插槽的最终落点
slot-cmp.tsx 是最底层的容器,仅声明了一个默认插槽:
@Component({ tag: 'slot-cmp', styles: 'slot-cmp { display: inline-block; }', }) export class SlotCmp { render() { return ( <Host> <slot /> </Host> ); } }整条链路可以概括为:
slot-cmp-container(shadow) └─ slot-cmp(内含 <slot/>) └─ slot-parent-cmp(内含 <slot/> 转发给下一层) └─ slot-cmp(内含 <slot/>,最终落点)标签文本One/Two/Three(来自labelProp)与插槽内容最终都会渲染到最内层slot-cmp的默认插槽位置。
四、依赖关系与 Mermaid 依赖图
slot-parent-cmp的自动文档给出了完整的依赖信息:
- Used by:
slot-cmp-container(即谁在模板中使用了该组件) - Depends on:
slot-cmp(即该组件的模板引用了哪些自定义元素) - Graph:由上述两个方向合并而成的 Mermaid 依赖图
这张图与 slot-cmp-container/readme.md 中的依赖图互为印证:容器同时依赖slot-cmp与slot-parent-cmp,而slot-parent-cmp依赖slot-cmp,因此容器文档的图中有slot-cmp-container --> slot-cmp与slot-cmp-container --> slot-parent-cmp两条边。style行只是 Markdown 生成器的视觉标记,用于高亮"当前文档所属组件"节点。
依赖图的生成逻辑可追溯至 src/compiler/docs/readme/markdown-dependencies.ts(Dependencies 小节与 Mermaid 图),它依赖编译期收集的组件依赖元数据——即编译器在分析 JSX 模板时,为每个组件记录下它引用的其他自定义元素集合。
五、插槽顺序的正确性验证:e2e 测试
自动文档不会告诉你"插槽是否正确渲染",这由 e2e 测试保证。slot-cmp-container.e2e.ts 用 Stencil 测试运行时newE2EPage起了一个真实浏览器页面:
import { newE2EPage } from '@stencil/core/testing'; describe('Slots', () => { it('should render the slots in the correct order', async () => { const page = await newE2EPage({ html: '<slot-cmp-container></slot-cmp-container>' }); const element = await page.find('slot-cmp-container'); expect(element.shadowRoot.textContent).toContain('OneTwoThree'); }); });断言textContent包含连续的OneTwoThree,这同时验证了三件事:
- 三个
slot-parent-cmp的label文本按文档顺序渲染; - 每层
<slot />转发没有丢失或乱序内容; - Shadow DOM 的插槽分配(slot assignment)在组件树嵌套后依然正确。
这正是仓库中大量 wdio 插槽测试(如 slot-basic、slot-nested-order、slot-reorder 等)所覆盖主题的 e2e 侧缩影。若想深入底层机制,可继续阅读 dom-extras.ts(其中包含针对 slotted 节点在 scoped 组件中的prepend/append/insertAdjacent*等方法的修补实现)以及 vdom-render.ts 中的插槽投影逻辑。
六、如何在自己的组件库中复现这套"自动文档 + 插槽"
6.1 开启 docs-readme 输出
自动生成readme.md依赖 Stencil 配置中的docs-readme输出目标。仓库 test/end-to-end/stencil.config.ts 即为端到端测试项目启用了该输出目标;组件源码目录下的readme.md头部注释<!-- Auto Generated Below -->就是其产物标记。运行stencil build时,编译器会扫描所有组件并刷新对应文档。
6.2 撰写插槽时遵循的实践
- 默认插槽:直接写
<slot />,文档 Slots 表格中 Slot 列为空白,Description 可写 "The default slot"(描述文本来自源码中 JSX 注释或默认约定,具体以你配置的文档生成行为为准); - 具名插槽:写
<slot name="xxx" />,文档中会以`"xxx"`形式呈现(见 markdown-slots.ts 的处理逻辑); - 插槽转发:中间层组件不要吞掉子内容,而是把
<slot />继续传给目标子组件,如上文slot-parent-cmp所示; - 验证:仿照 slot-cmp-container.e2e.ts 编写 e2e 断言,用
shadowRoot.textContent或page.find校验最终渲染文本与顺序。
七、小结
slot-parent-cmp的自动文档虽小,却完整映射出一个 Stencil 插槽嵌套组件的全部关键事实:@Prop属性声明与默认值、默认插槽的声明与转发、组件间依赖关系与可视化依赖图、以及 e2e 对渲染顺序的验证。理解它,就等于理解了 Stencil 文档生成器(src/compiler/docs/readme)如何从源码元数据产出 API 文档,也掌握了编写"可转发插槽"组件时的标准姿势。后续可继续阅读 test/wdio 下 slot 系列目录(如 slot-nested-order、slot-forwarded-slot 相关用例)与 nested-slot-forwarding.spec.tsx,进一步探索更复杂的插槽投影边界情况。
- 开发工具
- 前端
- 前端构建
【免费下载链接】stencil
A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, (+ more) and traditional web applications from a single, framework-agnostic codebase.
相关推荐
Stencil 组件插槽实战解析:从 slot-cmp 组件读懂默认 Slot、依赖图与自动生成文档
Stencil 组件插槽实战解析:从 slot cmp 组件读懂默认 Slot、依赖图与自动生成文档 slot cmp 是 Stencil 官方端到端(end
开发工具前端前端构建Stencil 组件 Slot 嵌套组合与自动生成文档实战:以 slot-cmp-container 为例
Stencil 组件 Slot 嵌套组合与自动生成文档实战:以 slot cmp container 为例 在 Stencil 的端到端测试工程 test/en
开发工具前端前端构建Nuxt Content 组件插槽(Slot)机制深度解析
Nuxt Content 组件插槽 Slot 机制深度解析 什么是组件插槽 在 Nuxt Content 项目中,组件插槽 Slot 是一种强大的内容注入机制,
前端CMS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考