第2章 Material 3 组件中的 Slot 列表:Button、Card、Dialog

Slot(插槽)是 Material 3 组件体系中的核心扩展机制——它允许开发者在保留组件交互逻辑与视觉基准的前提下,向组件内部注入自定义内容或子组件。本章系统梳理三个高频组件(Button、Card、Dialog)的 Slot 定义、数据类型与使用规则,为后续实现章节打下结构化基础。

2.1 Slot 机制概述

在 Material 3 的组件模型中,Slot 是一个具名占位符,组件通过声明 Slot 列表向外界开放内容注入点。每个 Slot 通常绑定一组类型约束(如仅允许 Icon 或 Text 组件),并在组件内部按固定层级渲染。理解 Slot 的命名规范与嵌套关系,是正确使用组件扩展能力的前提。

维度说明
定义位置组件构造函数的参数或子组件属性中声明
数据类型Slot<T>、Slot<Node> 或具体组件类型引用
渲染时机组件内部按固定顺序依次渲染所有已赋值的 Slot
默认值可提供空 Slot 或占位组件,避免未赋值时出现空白
设计核心:Slot 不改变组件的外层 DOM 结构与布局策略,仅替换或追加内部内容块。这意味着组件的 elevation、shape、ripple 等样式层不受 Slot 内容影响。

2.2 Button 组件 Slot 列表

Button 系列组件(FilledButton、OutlinedButton、TextButton、ElevatedButton)共享同一套 Slot 接口。以下列出所有可用 Slot 及其类型说明:

Slot 名称类型约束必填说明
iconSlot<Icon>否位于标签左侧的前置图标,通常为 18dp 尺寸
labelSlot<Text>是按钮主要文字内容,支持动态文本更新
trailingIconSlot<Icon>否位于标签右侧的后置图标,较少使用
overlaySlot<Box>否覆盖在按钮整体上方的内容层,用于加载指示器等
实战要点:
  • label 是唯一必填 Slot,即使内容为空字符串也必须传入 Text 组件。
  • icon 与 trailingIcon 同时赋值时,组件内部按 icon → label → trailingIcon 顺序渲染。
  • overlay Slot 使用 Positioned.fill 定位,默认不拦截点击事件(需手动设置 pointerEvents)。

以下示例展示在 Flutter 中使用 FilledButton 同时赋值 icon 与 label 的典型写法:

FilledButton(
  onPressed: () {},
  icon: const Icon(Icons.add),
  label: const Text('新建任务'),
)

2.3 Card 组件 Slot 列表

Material 3 的 Card 组件提供比 Button 更丰富的 Slot 结构,支持媒体、头部、内容和操作栏四段布局。所有 Slot 均为可选,组件在不赋值时自动隐藏对应区域。

Slot 名称类型约束默认渲染位置说明
mediaSlot<Image>顶部全宽区域通常为 16:9 或 4:3 比例的图片,裁剪方式由组件固定
headerSlot<Widget>媒体下方、内容上方承载标题、副标题、头像等行内组合
contentSlot<Text>头部下方、操作栏上方主要描述文字,支持文本溢出省略
actionsSlot<Row>底部右对齐操作按钮组,组件内部自动添加间距与对齐
footerSlot<Widget>最底部通栏用于放置元信息、标签或副操作
注意:media Slot 的宽高比由 Card 组件的 mediaShape 与 mediaGap 联合控制,传入的图片不会自动裁剪;建议外部预裁剪或使用 BoxFit.cover。

一个包含头部、内容和操作栏的典型 Card 构造片段:

Card(
  header: ListTile(
    leading: CircleAvatar(child: Text('A')),
    title: Text('项目概览'),
    subtitle: Text('2025-02-21'),
  ),
  content: const Text('Material 3 Slot API 是组件扩展的核心通道。'),
  actions: Row(
    children: [
      TextButton(onPressed: () {}, label: const Text('详情')),
      FilledButton(onPressed: () {}, label: const Text('编辑')),
    ],
  ),
)

2.4 Dialog 组件 Slot 列表

Dialog 组件采用“图标—标题—内容—操作”的垂直层叠结构,Slot 定义清晰且类型严格。与 Button 和 Card 不同,Dialog 的 Slot 赋值直接影响对话框的语义层级(如 icon 赋值后组件自动启用顶部圆角与间距调整)。

Slot 名称类型约束必填说明
iconSlot<Icon>否顶部居中图标,赋值后 Dialog 自动增加上内边距
headlineSlot<Text>是对话框主标题,使用 24sp 字重 Medium
contentSlot<Text>否正文描述,最大高度受限(可滚动)
actionsSlot<Row>否操作按钮区,组件自动右对齐并添加 8dp 间距
最佳实践:当 icon 与 headline 同时使用时,建议 icon 使用语义明确的 Material 图标(如 Icons.info_outline),且颜色保持 onSurfaceVariant 以对齐 Dialog 的视觉层级。

以下是一个包含完整四层 Slot 的 Dialog 构造示例:

AlertDialog(
  icon: const Icon(Icons.warning_amber_rounded),
  headline: const Text('确认删除'),
  content: const Text('此操作将永久删除所选文件,不可恢复。'),
  actions: Row(
    children: [
      TextButton(onPressed: () {}, label: const Text('取消')),
      FilledButton(onPressed: () {}, label: const Text('删除')),
    ],
  ),
)

2.5 三个组件 Slot 结构对比

将上述三个组件的 Slot 列表按“层级深度”“必填数量”“类型丰富度”三个维度进行横向比较:

组件Slot 总数必填数嵌套层级类型严格度典型用途
Button41(label)1 层(扁平)高(Icon/Text 明确)操作入口、表单提交
Card502~3 层(含嵌套 Row/Column)中(Widget 宽泛)列表项、概览卡片、媒体展示
Dialog41(headline)1 层(垂直堆叠)高(Icon/Text/Row 明确)确认框、提示框、详情弹窗
关键发现:Card 组件虽然 Slot 数量最多(5 个),但类型约束最为宽松(Slot<Widget>),适合高度自定义场景;Button 与 Dialog 则通过窄类型约束保证组件语义一致性。

2.6 Slot 层级关系图

下方 SVG 图展示了 Button、Card、Dialog 三个组件的 Slot 内部渲染层级关系,帮助理解 Slot 在组件树中的实际位置:

Material 3 组件 Slot 层级结构图 Button · Card · Dialog Slot 层级关系 Button icon (Slot<Icon>) label (Slot<Text>) ★ 必填 trailingIcon (Slot<Icon>) overlay Slot(全透明覆盖层) Card media (Slot<Image>) header (Slot<Widget>) content (Slot<Text>) actions (Slot<Row>) footer (Slot<Widget>) 所有 Slot 均为可选(0 必填) Dialog icon (Slot<Icon>) headline (Slot<Text>) ★ 必填 content (Slot<Text>) actions (Slot<Row>) content 最大高度受限(滚动) 必填 Slot 可选 Slot 后置/底部 Slot 跨组件设计关联

2.7 常见误区与调试指引

根据社区反馈与项目实践,以下列出 Slot 使用中最容易踩中的三个误区:

  1. 将必填 Slot 当作可选处理:Button 的 label 与 Dialog 的 headline 在编译期不会报错,但运行时会导致组件不渲染或布局坍缩。调试时优先检查必填 Slot 是否已赋值。
  2. Slot 类型不匹配导致隐式转换失败:部分组件内部使用 is 判断 Slot 类型,传入 Container 而非 Icon 可能导致图标区空白。应严格遵循类型约束表。
  3. 多个 Slot 同时赋值时的顺序依赖:Card 的 header 与 content 都依赖 media 的间距计算;若 media 为空但 header 存在,组件仍会保留媒体占位空间。建议按 media → header → content → actions → footer 顺序赋值。
调试建议:在 Flutter 中使用 SlotInspector 或打印 widget.slotList 运行时信息,可以快速确认每个 Slot 的赋值状态与类型。对于 Web 端(Lit/Material Web),使用浏览器 DevTools 的组件树面板查看 Slot 节点是否被正确分发。

2.8 稳定性与性能提示

Slot 机制本身不会引入额外性能开销——组件内部仅在构建时遍历 Slot 列表一次。但在以下场景中需要关注优化:

  • 动态 Slot 切换:频繁替换 icon 或 content 时,建议使用 key 属性保持组件状态稳定,避免不必要的重建。
  • 大体积 Slot 内容:Card 的 media Slot 传入高分辨率图片时,应在外部预先缩放至组件所需尺寸,防止组件内部多次 layout 计算。
  • 嵌套 Slot 层级过深:Dialog 的 actions Slot 内部尽量避免再嵌套多层 Row/Column,以降低布局计算复杂度。

至此,Button、Card、Dialog 三个核心组件的 Slot 列表已完整呈现。下一维度将进入 Slot 的类型系统与类型安全约束详解,为自定义组件 Slot 设计提供类型理论基础。