【免费下载链接】ant-design-blazor
基于 Ant Design 与 Blazor 的前端组件库。让开发者解放生产力,实现更大价值。
在 Ant Design Blazor 组件库中,Collapse(折叠面板)默认允许同时展开多个面板,而开启 Accordion 属性后,组件会切换为手风琴模式:同一时刻只允许一个面板处于展开状态,展开新面板时其余面板自动收起。本文以官方演示文档 accordion.md 为核心,结合组件源码与完整 API,讲解手风琴模式的用法、底层实现原理及周边配置,帮助你在 Blazor 项目中准确、高效地落地这一交互模式。
一、手风琴模式是什么
手风琴(Accordion)是折叠面板的一种特殊形态。官方文档 index.zh-CN.md 中明确指出其适用场景:
- 对复杂区域进行分组和隐藏,保持页面的整洁;
- 手风琴是一种特殊的折叠面板,只允许单个内容区域展开。
与之相对,普通模式下可以同时展开多个面板(参见 Basic.md 的演示:"可以同时展开多个面板")。手风琴模式的核心特征是互斥展开:用户点击某个面板的标题时,其他已展开的面板会被强制收起,保证页面任意时刻只有一个内容区可见。
二、手风琴模式的最小可运行示例
在 Collapse 组件上设置 Accordion 属性(布尔值)即可开启手风琴模式。官方演示 Accordion.razor 给出了完整的最小示例:
<Collapse DefaultActiveKey="@(new[]{"1"})" Accordion>
<Panel Header="This is panel header 1" Key="1">
<p>@text</p>
</Panel>
<Panel Header="This is panel header 2" Key="2">
<p>@text</p>
</Panel>
<Panel Header="This is panel header 3" Key="3">
<p>@text</p>
</Panel>
</Collapse>
@code{
string text = @"
A dog is a type of domesticated animal.
Known for its loyalty and faithfulness,
it can be found as a welcome guest in many households across the world.
";
}
几个关键点:
Accordion为boolean类型,默认值false,设置为true即进入手风琴模式;DefaultActiveKey接收string[]类型的 key 数组,用于设置初始化时展开的面板。示例中传入new[]{"1"},因此页面加载时第一个面板(Key="1")处于展开状态;Panel的Key是每个面板的唯一标识,手风琴模式下互斥判断正是基于这些 key 展开的;- 面板内容(
<p>@text</p>)可自由替换为任意 Blazor 内容片段。
三、Collapse 与 Panel 的完整 API
为了让手风琴模式的使用更灵活,需要掌握 Collapse 与 Panel 的全部参数。以下参数表摘自 index.zh-CN.md,并结合源码 Collapse.razor.cs 与 Panel.razor.cs 补充了默认值与类型细节。
Collapse 参数
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
Accordion | 是否每次只打开一个 tab | boolean | false |
Bordered | 是否有边框 | boolean | true |
ExpandIconPosition | 设置图标位置 | 'left' \| 'right' | left |
Animation | 是否开启动画 | boolean | false |
DefaultActiveKey | 默认展开的 Panel 的 Key 数组 | string[] | Array.Empty<string>() |
ActiveKeys | 当前展开的 Panel 的 Key 数组,支持双向绑定 | string[] | - |
ActiveKeysChanged | ActiveKeys 的双向绑定回调 | EventCallback<string[]> | - |
OnChange | 展开面板发生变化时的回调 | EventCallback<string[]> | - |
ExpandIcon | 展开图标类型 | string | IconType.Outline.Right |
ExpandIconTemplate | 自定义展开图标内容(优先于 ExpandIcon) | RenderFragment<bool> | - |
Panel 参数
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
Disabled | 禁用后的面板展开与否将无法通过用户交互改变 | boolean | false |
Header | 面板头内容 | string \| RenderFragment | - |
ExpandedIcon | 自定义切换图标 | string \| RenderFragment | - |
Extra | 自定义渲染每个面板右上角的内容 | string \| RenderFragment | - |
ShowArrow | 是否展示箭头 | boolean | true |
Active | 面板是否展开,可双向绑定 | boolean | - |
ActiveChange | 面板展开回调 | EventCallback<boolean> | - |
Key | 面板唯一标识 | string | - |
OnActiveChange | 该面板展开状态变化时的回调 | EventCallback<bool> | - |
实例方法
| 名称 | 说明 |
|---|---|
Activate(string[] activeKeys) | 展开指定 key 对应的 Panel |
Deactivate(string[] inactiveKeys) | 关闭指定 key 对应的 Panel |
Activate / Deactivate 方法在源码 Collapse.razor.cs 中实现:Activate 会展开传入 key 对应的面板,并且在手风琴模式下自动收起其余所有面板;Deactivate 则关闭指定 key 的面板。需要注意,在手风琴模式下调用 Activate 传入多个 key 时,后处理的逻辑会让互斥规则自动生效。
四、手风琴模式的底层实现原理
手风琴模式的互斥逻辑并非由 CSS 实现,而是由 Collapse 组件的 TogglePanelState 方法在 C# 侧统一协调,见 Collapse.razor.cs:
internal void TogglePanelState(Panel panel)
{
if (panel == null) return;
var newActiveKeys = new List<string>(EffectiveActiveKeys);
// 手风琴模式:收起其他所有已展开的面板
if (this.Accordion && !panel.Active)
{
this.Items.Where(item => item != panel && item.Active)
.ForEach(item => item.SetActiveInt(false));
newActiveKeys.Clear();
}
var isActive = !panel.Active;
panel.SetActiveInt(isActive);
if (isActive)
{
if (!newActiveKeys.Contains(panel.Key))
newActiveKeys.Add(panel.Key);
}
else
{
newActiveKeys.Remove(panel.Key);
}
var selectedKeys = newActiveKeys.ToArray();
if (ActiveKeys != null)
{
if (ActiveKeysChanged.HasDelegate)
ActiveKeysChanged.InvokeAsync(selectedKeys);
}
else
{
_internalActiveKeys = selectedKeys;
}
if (OnChange.HasDelegate)
OnChange.InvokeAsync(selectedKeys);
if (panel.OnActiveChange.HasDelegate)
panel.OnActiveChange.InvokeAsync(panel.Active);
}
从源码中可以提炼出手风琴模式的三条核心行为规则:
- 点击触发:用户点击面板标题时,
Panel的OnHeaderClick方法会调用Collapse.TogglePanelState(this),前提是面板未被Disabled禁用(见 Panel.razor.cs); - 互斥收起:当点击的是一个未展开的面板且处于手风琴模式时,
Items.Where(item => item != panel && item.Active)会找出所有其他处于展开状态的面板并逐一收起; - 状态同步:展开状态会统一汇聚到
ActiveKeys数组并通过ActiveKeysChanged、OnChange回调对外通知,支持受控与双向绑定两种用法。
组件内部通过 EffectiveActiveKeys(ActiveKeys ?? _internalActiveKeys)来决定"受控"与"非受控"两种模式:当外部传入 ActiveKeys 时,组件进入受控状态,面板开关完全由外部数据驱动(对应下文的外控示例);否则使用内部维护的 _internalActiveKeys 作为默认状态。
五、手风琴模式与外控状态结合
手风琴模式同样支持通过 @bind-ActiveKeys 从外部控制展开的面板。官方演示 ControlledActiveKeys.razor 展示了如何用按钮切换面板状态:
<Collapse @bind-ActiveKeys="@_activeKeys">
<Panel Key="1" Header="This is panel header 1">
<p>A dog is a type of domesticated animal. ...</p>
</Panel>
<Panel Key="2" Header="This is panel header 2">
<p>A cat is a type of domesticated animal. ...</p>
</Panel>
<Panel Key="3" Header="This is panel header 3">
<p>A bird is a type of wild or domesticated animal. ...</p>
</Panel>
</Collapse>
<br />
<Space>
<SpaceItem>
<Button Type="@ButtonType.Primary" OnClick="@(() => TogglePanel("1"))">Toggle Panel 1</Button>
</SpaceItem>
<SpaceItem>
<Button Type="@ButtonType.Primary" OnClick="@(() => TogglePanel("2"))">Toggle Panel 2</Button>
</SpaceItem>
<SpaceItem>
<Button Type="@ButtonType.Primary" OnClick="@(() => TogglePanel("3"))">Toggle Panel 3</Button>
</SpaceItem>
</Space>
@code {
private string[] _activeKeys = Array.Empty<string>();
private void TogglePanel(string key)
{
if (_activeKeys.Contains(key))
{
_activeKeys = _activeKeys.Where(k => k != key).ToArray();
}
else
{
_activeKeys = _activeKeys.Append(key).ToArray();
}
}
}
要点:把 Collapse 的 ActiveKeys 通过 @bind- 绑定到组件字段后,展开/折叠完全由外部数组驱动。若将该示例与 Accordion 属性组合使用,即可在受控状态下获得手风琴的互斥效果——此时外部每次只应向 ActiveKeys 保留一个 key。
六、手风琴模式下的面板定制
手风琴模式的每个 Panel 依然支持全部自定义能力,常见的组合方式如下:
- 隐藏箭头:设置
ShowArrow="false",面板标题栏不再显示展开箭头(对应 noarrow.md 演示); - 无边框:在
Collapse上设置Bordered="false",组件会添加ant-collapse-borderless样式类(见 Collapse.razor.cs 的SetClassMap),形成紧凑无边框布局; - 自定义右侧内容:
Panel的Extra/ExtraTemplate参数用于渲染面板右上角的内容,渲染位置由 Panel.razor 中的ant-collapse-extra容器承载; - 自定义图标:
ExpandIconTemplate接收一个bool(当前面板是否展开)参数,可据此动态渲染图标;未设置时默认使用Collapse.ExpandIcon指定的图标(默认IconType.Outline.Right),并通过Rotate在展开/收起时旋转 90°; - 禁用面板:
Panel设置Disabled后,点击标题不会触发任何展开操作(源码中OnHeaderClick会直接跳过)。
需要注意的是,手风琴模式下仍可以嵌套使用 Collapse:外层手风琴的某个面板内部可以再放一个独立的 Collapse 甚至又一个手风琴(参考 Mix.razor 演示),各层级的展开状态互不影响。
七、动画与视觉细节
Collapse的Animation属性默认关闭。开启后,面板展开/收起会走 Panel.razor.cs 中的HandleExpand/HandleCollapse动画流程:通过 JS 互操作读取内容区高度,配合ant-motion-collapse-*系列样式类与height/opacity过渡实现平滑展开收起,动画总时长约 550ms(100ms 启动 + 450ms 过渡);- 箭头位置由
ExpandIconPosition控制(left/right),对应的样式类为ant-collapse-icon-position-left/ant-collapse-icon-position-right; - RTL 场景下组件会自动追加
ant-collapse-rtl样式类。
八、总结与选择建议
| 场景 | 推荐配置 |
|---|---|
| 同时展示多个独立内容区 | 默认模式,不设置 Accordion |
| 空间受限、每次只聚焦一个内容区 | 设置 Accordion(本文核心) |
| 需要外部按钮控制开关 | 组合使用 @bind-ActiveKeys 与外控逻辑 |
| 紧凑型信息展示 | Accordion + Bordered="false" |
| 需要平滑过渡 | Accordion + Animation="true" |
手风琴模式是 Collapse 组件在"内容互斥展示"场景下的标准答案。它由 Collapse.razor.cs 中的 TogglePanelState 在 C# 侧统一管理互斥逻辑,配合 DefaultActiveKey、ActiveKeys、OnChange 等参数即可覆盖从"开箱即用"到"完全受控"的各类需求;结合 Panel 的 Header、Extra、ShowArrow、Disabled 等参数,可以定制出贴合业务形态的手风琴交互。动手实践时,可直接参考官方演示 Accordion.razor 与完整 API 文档 index.zh-CN.md。
【免费下载链接】ant-design-blazor
基于 Ant Design 与 Blazor 的前端组件库。让开发者解放生产力,实现更大价值。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



