- 前端
- UI组件
- 设计系统
【免费下载链接】ant-design-blazor
基于 Ant Design 与 Blazor 的前端组件库。让开发者解放生产力,实现更大价值。
Modal(对话框)是 Ant Design Blazor 组件库中最常用的反馈型组件之一:它无需跳转新页面,就能在当前页面之上浮动一层遮罩与对话框,用于收集用户反馈、展示信息或执行确认操作。本文以官方文档(index.en-US.md)为骨架,结合仓库源码与官方示例,系统讲解Modal组件的全部配置参数、ModalService服务式调用、ConfirmService确认框、模板化弹窗(FeedbackComponent)等核心用法,帮助你写出可维护、可复用的对话框代码。
什么时候使用 Modal
当需要用户与应用交互,但又不想跳转到新页面打断用户的工作流时,可以使用Modal在当前页面上创建一个新的浮动层,用来获取用户反馈或展示信息。另外,如果需要展示一个简单的确认对话框,可以使用ModalService.Confirm()等方法。
在 Modal.razor.cs 中,组件被定义为public partial class Modal,并通过[Documentation(DocumentationCategory.Components, DocumentationType.Feedback, ...)]注册为"反馈(Feedback)"类组件,从源码结构看,Modal 与 Message、Notification 等共同构成了反馈体系。
Modal 组件参数详解(API)
Modal组件支持通过声明式标签(<Modal>)在 razor 页面中直接使用。下面是官方文档列出的全部参数及其说明、类型与默认值:
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| AfterClose | Modal 完全关闭后触发的回调 | EventCallback | - |
| BodyStyle | Modal body 元素的内联样式(如高度、内边距等) | string | - |
| CancelText | 取消按钮的文字 | string | RenderFragment | Cancel |
| Centered | 是否垂直居中显示 | bool | false |
| Closable | 是否在右上角显示关闭(x)按钮 | bool | true |
| CloseIcon | 自定义关闭图标 | RenderFragment | - |
| ConfirmLoading | 是否为确定按钮应用 loading 视觉效果 | bool | false |
| DestroyOnClose | 关闭时是否卸载子组件 | bool | false |
| Header | 头部内容,设为Header="null"时不显示默认头部 | RenderFragment | - |
| Footer | 底部内容,设为Footer="null"时不显示默认按钮 | string | RenderFragment | 确定与取消按钮 |
| ForceRender | 是否强制渲染 Modal | bool | false |
| GetContainer | Modal 挂载的 DOM 节点 | ElementReference? | document.body |
| Keyboard | 是否支持按 Esc 键关闭 | bool | true |
| Mask | 是否显示遮罩 | bool | true |
| MaskClosable | 点击遮罩(Modal 外部区域)是否关闭 | bool | true |
| MaskStyle | 遮罩元素的内联样式 | string | - |
| OkText | 确定按钮的文字 | string | RenderFragment | OK |
| OkType | 确定按钮的类型 | string | primary |
| OkButtonProps | 确定按钮的 props | ButtonProps | - |
| CancelButtonProps | 取消按钮的 props | ButtonProps | - |
| Style | 浮动层的样式,通常至少用来调整位置 | string | - |
| Title | 对话框标题,若 TitleTemplate 非空则以 TitleTemplate 为准 | string | null |
| TitleTemplate | 对话框标题模板 | RenderFragment | null |
| Visible | 对话框是否可见 | bool | - |
| Width | 对话框宽度 | string | double | 520 |
| WrapClassName | 对话框容器元素的类名 | string | - |
| ZIndex | Modal 的 z-index | int | 1000 |
| OnCancel | 用户点击遮罩、右上角关闭按钮或取消按钮时触发 | EventCallback<MouseEventArgs> | - |
| OnOk | 用户点击确定按钮时触发 | EventCallback<MouseEventArgs> | - |
| Draggable | 是否允许通过 Header 拖动 Modal(为 true 时,Title 与 TitleTemplate 至少要有值) | bool | false |
| DragInViewport | Draggable 为 true 时,是否仅允许在视口内拖动 | bool | true |
| MaxBodyHeight | Modal 内容最大高度 | string? | null |
| Maximizable | 是否显示最大化按钮 | bool | false |
| MaximizeBtnIcon | 未最大化时最大化按钮的图标 | RenderFragment | fullscreen |
| RestoreBtnIcon | 已最大化时恢复按钮的图标 | RenderFragment | fullscreen-exit |
| DefaultMaximized | 初始化时 Modal 是否直接最大化 | bool | false |
| Resizable | Modal 是否可调整大小 | bool | false |
参数背后的源码实现
这些参数并非只是文档声明,在 Modal.razor.cs 中均有对应的[Parameter]属性。几个值得注意的细节:
- 默认值与生命周期:
Visible默认false,Closable默认true,MaskClosable默认true(见 Modal.razor.cs)。Keyboard默认true,即默认支持 Esc 关闭。 - 宽度计算:
Width的类型是OneOf<string, double>。传入 double(如 520)时,内部GetWidth()会拼成"520px";传入 string(如"80%")时则原样使用(见 Modal.razor.cs)。 - 图标默认值:
CloseIcon、MaximizeBtnIcon、RestoreBtnIcon的默认值定义在DialogOptionsBase中,分别为close、fullscreen、fullscreen-exit三个 Outline 主题图标(见 DialogOptionsBase.cs)。 - ConfirmLoading 与 OkButtonProps 联动:在服务式调用使用的 ModalOptions.cs 中,
ConfirmLoading实际上读写的是OkButtonProps.Loading——设置ConfirmLoading = true等价于把确定按钮置为加载中状态。 - 可见性双向绑定:
Visible与VisibleChanged成对出现,因此@bind-Visible="_visible"是声明式用法中最常见的绑定方式。
基本用法
官方 Basic.razor 演示了最简声明式用法:
<Button Type="ButtonType.Primary" OnClick="@(()=>{ _visible = true; })"> Open Modal </Button> <Modal Title="BasicModal" @bind-Visible="@_visible"> <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> @code{ bool _visible = false; }状态保持与 DestroyOnClose
注意:默认情况下,Modal 的状态会在其组件生命周期内被保留。如果你希望每次打开时都是全新状态,请设置
DestroyOnClose。
这是官方文档给出的关键提示:DestroyOnClose = false(默认)时,Modal 关闭后并不会从 DOM 中移除,子组件的状态(如表单输入值)得以保留;而DestroyOnClose = true时,关闭动画结束后子组件会被卸载,下次打开即重新初始化。
这一行为在 ModalContainer.razor.cs 中体现得非常直观:关闭事件触发后先将Visible置为false,等待 250ms 关闭动画,然后仅当DestroyOnClose为 true 时才把modalRef从容器列表中移除并重新渲染。
ModalService:服务式创建与命令式控制
声明式<Modal>适合把弹窗内嵌在页面中;但当需要在任意位置(事件处理、服务调用、甚至是路由变化时)弹出对话框时,ModalService才是更合适的选择。
前置条件:添加 AntContainer
请确认
<AntContainer />组件已经添加到App.Razor中。
AntContainer是消息类组件的承载容器。在 AntContainer.razor 中可以看到它渲染了Notification、Message、ComfirmContainer、DrawerContainer、ModalContainer与ImagePreviewContainer等容器组件——ModalService创建的所有弹窗都由ModalContainer订阅事件并挂载渲染。
确认对话框(Confirm)类方法
根据内容性质,ModalService提供多种展示方法:
ModalService.InfoModalService.SuccessModalService.ErrorModalService.WarningModalService.ConfirmModalService.CreateAsyncModalService.ConfirmAsyncModalService.InfoAsyncModalService.SuccessAsyncModalService.ErrorAsyncModalService.WarningAsyncModalService.UpdateConfirmAsyncModalService.DestroyConfirmAsyncModalService.DestroyAllConfirmAsyncModalService.CreateConfirmAsync
这些方法的源码分布在 ModalServiceForConfirm.cs 中。其中Info/Success/Error/Warning本质上是Confirm的"带图标 + 仅确定按钮"变体:例如Info(options)内部执行options.ConfirmIcon = ConfirmIcon.Info; options.OkCancel = false;后转发给Confirm(options)(见 ModalServiceForConfirm.cs)。
对话框(Modal)类方法
ModalService.CreateModalAsync
在 ModalServiceForModal.cs 中,CreateModal会创建ModalRef、把options.ModalRef与CreateByService = true写入配置,随后通过OnModalOpenEvent通知ModalContainer渲染。CreateModalAsync已被标记为[Obsolete("Use the CreateModal instead.")],但为保持向后兼容仍可用(见 ModalServiceForModal.cs)。
返回值与 Task 语义
ConfirmAsync、InfoAsync、SuccessAsync、ErrorAsync、WarningAsync会返回Task<bool>,可用于判断用户点击的是确定按钮(true)还是取消按钮(false)。
从源码看,ConfirmAsync内部创建带TaskCompletionSource<ConfirmResult>的ConfirmRef,然后通过ContinueWith(t => t.Result == ConfirmResult.OK)将ConfirmResult映射为布尔值(见 ModalServiceForConfirm.cs)。
通过引用更新与关闭
所有
ModalService.Method都会返回一个引用(reference),之后可以通过该引用更新和关闭对话框。
ConfirmOptions config = new ConfirmOptions(); var modelRef = await ModalService.Info(config); modelRef.UpdateConfirmAsync(); ModalService.DestroyConfirmAsync(modelRef);ModalRef(见 ModalRef.cs)与ConfirmRef(见 ConfirmRef.cs)都继承自FeedbackRefWithOkCancelBase(定义于 FeedbackRefBase.cs),提供OpenAsync()、CloseAsync()、UpdateConfigAsync()等命令式方法。此外:
ModalRef.SetConfirmLoading(bool loading)可动态切换确定按钮的加载状态(见 ModalRef.cs);ConfirmRef<TResult>、ModalRef<TResult>额外支持OkAsync(result)/CancelAsync(result)带返回值回调。
批量销毁:DestroyAllConfirmAsync
ModalService.DestroyAllConfirmAsync()可以销毁全部确认对话框(ModalService.Info/Success/Error/Warning/Confirm创建的)。官方文档建议:通常在路由变化事件中调用它来自动销毁确认弹窗,避免为每个弹窗分别持有引用并逐一关闭(逐个维护引用对大量弹窗来说过于复杂)。其实现为触发OnConfirmCloseAllEvent(见 ModalServiceForConfirm.cs),而ModalContainer也会在NavigationManager.LocationChanged时清空引用列表(见 ModalContainer.razor.cs)。
ConfirmService:像 Windows MessageBox 一样使用
IConfirmService.Show用于展示一个类似 Windows MessageBox 的简单确认框,它与ModalService有本质区别:
- ModalService只能创建 OK-Cancel 确认框,返回
ConfirmRef或"确定按钮是否被点击"的布尔值; - ConfirmService返回
ConfirmResult枚举,可以精确得知用户点击了哪个按钮。
源码实现
ConfirmService.cs 的Show方法接收内容、标题、按钮组合、图标、按钮选项与自动聚焦按钮,内部构造ConfirmOptions并通过OnOpenEvent交给ComfirmContainer渲染,最终通过TaskCompletionSource<ConfirmResult>异步返回结果。
ConfirmResult 与 ConfirmButtons
ConfirmResult是标志枚举(见 ConfirmResult.cs):
| 值 | 含义 |
|---|---|
| None | 无 |
| OK | 确定 |
| Cancel | 取消 |
| Abort | 中止 |
| Retry | 重试 |
| Ignore | 忽略 |
| Yes | 是 |
| No | 否 |
ConfirmButtons(见 ConfirmButtons.cs)支持六种按钮组合:
| 枚举值 | 按钮组合 |
|---|---|
| OK | 仅确定 |
| OKCancel | 确定 + 取消 |
| YesNo | 是 + 否 |
| RetryCancel | 重试 + 取消 |
| AbortRetryIgnore | 中止 + 重试 + 忽略 |
| YesNoCancel | 是 + 否 + 取消 |
ConfirmIcon(见 ConfirmIcon.cs)支持None / Info / Warning / Error / Success / Question六种状态,分别映射到info-circle、exclamation-circle、close-circle、check-circle、question-circle图标。
完整示例
官方 Confirm_Service.razor 演示了全部按钮组合与图标,核心调用方式:
@inject IConfirmService _confirmService @inject IMessageService _message private async Task ShowConfirm(ConfirmButtons confirmButtons) { var content = "Here is a blocking confirm, you can get OK or cancel button is click"; var title = "Info"; var confirmResult = await _confirmService.Show(content, title, confirmButtons); _message.Info($"{confirmResult} button is clicked", 2); }Show的重载签名支持自定义按钮属性:
await _confirmService.Show( content, title, ConfirmButtons.AbortRetryIgnore, ConfirmIcon.Error, new ConfirmButtonOptions() { Button1Props = new AntDesign.ButtonProps() { Type = AntDesign.ButtonType.Dashed }, Button2Props = new AntDesign.ButtonProps() { Type = AntDesign.ButtonType.Primary, Disabled = true } } );ConfirmOptions 参数表
ConfirmOptions是确认框的配置对象,继承自DialogOptionsBase(见 DialogOptionsBase.cs),默认宽度为 416。官方文档列出的参数如下:
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| CancelText | 取消按钮文字,等价于 Button2Props.ChildContent | string | RenderFragment | Cancel |
| Centered | 是否居中 | bool | false |
| ClassName | 容器类名 | string | - |
| Content | 内容 | string | RenderFragment | - |
| Icon | 自定义图标 | RenderFragment | - |
| Keyboard | 是否支持 Esc 关闭 | bool | true |
| Mask | 是否显示遮罩 | bool | true |
| MaskClosable | 点击遮罩是否关闭 | bool | false |
| OkText | 确定按钮文字,等价于 Button1Props.ChildContent | string | OK |
| OkType | 确定按钮类型,等价于 Button1Props.Type | string | primary |
| OkButtonProps | 确定按钮 props,等价于 Button1Props | ButtonProps | - |
| CancelButtonProps | 取消按钮 props,等价于 Button2Props | ButtonProps | - |
| Title | 标题,若 TitleTemplate 非空则以 TitleTemplate 为准 | string | null |
| TitleTemplate | 标题模板 | RenderFragment | null |
| Width | 宽度 | string | double | 416 |
| ZIndex | z-index | int | 1000 |
| OnCancel | 点击取消按钮时调用(仅在 ModalService 创建的 Confirm 中触发) | EventCallback<MouseEventArgs>? | null |
| OnOk | 点击确定按钮时调用(仅在 ModalService 创建的 Confirm 中触发) | EventCallback<MouseEventArgs>? | null |
| Button1Props | LTR 布局中最左侧按钮的 props | ButtonProps | Type = ButtonType.Primary |
| Button2Props | LTR 布局中左起第二个按钮的 props | ButtonProps | - |
| Button3Props | LTR 布局中最右侧按钮的 props | ButtonProps | - |
需要注意两点实现细节:
- OkText/CancelText 与 Button Props 的等价关系:在 ConfirmOptions.cs 中,
OkText、CancelText的读写实际映射到Button1Props.ChildContent、Button2Props.ChildContent;OkType映射到Button1Props.Type;OkButtonProps/CancelButtonProps分别是Button1Props/Button2Props的别名。所有按钮文字类型都是OneOf<string, RenderFragment>。 - 默认按钮文案由 Locale 驱动:
BuildButtonsDefaultOptions()会根据ConfirmButtons组合从ConfirmLocale读取默认文案,例如YesNoCancel会让按钮 2 默认带Danger样式(见 ConfirmOptions.cs)。
模板化弹窗:继承 FeedbackComponent
ModalService.CreateModalAsync<TComponent, TComponentOptions>与CreateConfirmAsync<TComponent, TComponentOptions, TResult>支持把任意组件渲染进弹窗,这是"弹窗中放表单/复杂业务组件"的标准姿势。
模板组件的写法
模板组件需继承FeedbackComponent<TComponentOptions>(或FeedbackComponent<TComponentOptions, TResult>),定义于 FeedbackComponent.cs。基类提供:
Options:从外部传入的组件配置;FeedbackRef:弹窗引用,可调用CloseFeedbackAsync()主动关闭弹窗;OnFeedbackOkAsync(ModalClosingEventArgs args)/OnFeedbackCancelAsync(ModalClosingEventArgs args):确定/取消回调,可通过args.Cancel = true阻止关闭;OkCancelRefWithResult:带返回值的确定/取消引用。
官方 ModalTemplateDemo.razor 是一个典型的表单模板:
@inherits FeedbackComponent<Form.demo.Basic.Model> <Form Model="@_model" OnFinish="OnFinish" OnFinishFailed="OnFinishFailed"> <FormItem Label="Username"> <Input @bind-Value="@context.Username" /> </FormItem> <FormItem Label="Password"> <InputPassword @bind-Value="@context.Password" /> </FormItem> ... </Form> @code{ private Form.demo.Basic.Model _model; protected override void OnInitialized() { _model = base.Options ?? new Form.demo.Basic.Model(); base.OnInitialized(); } private void OnFinish(EditContext editContext) { _ = base.FeedbackRef.CloseAsync(); // 表单提交成功后关闭弹窗 } }服务端创建模板弹窗
Modal_service_for_modal.razor 展示了完整流程:
var templateOptions = new Form.demo.Basic.Model(); templateOptions.Username = value; var modalConfig = new ModalOptions(); modalConfig.Title = "Basic Form"; modalConfig.OnCancel = async (e) => { await _modalRef.CloseAsync(); }; modalConfig.AfterClose = () => { /* 关闭后回写数据 */ return Task.CompletedTask; }; _modalRef = await ModalService .CreateModalAsync<ModalTemplateDemo, Form.demo.Basic.Model>(modalConfig, templateOptions); _modalRef.OnOpen = () => { /* ... */ return Task.CompletedTask; }; _modalRef.OnOk = () => { /* ... */ return Task.CompletedTask; }; _modalRef.OnCancel = () => { /* ... */ return Task.CompletedTask; }; _modalRef.OnClose = () => { /* ... */ return Task.CompletedTask; };带返回值的模板(TResult)
ConfirmTemplateDemo.razor 继承FeedbackComponent<string, string>,演示了"输入值与初始值一致才允许关闭并返回结果"的校验场景:
public override async Task OnFeedbackOkAsync(ModalClosingEventArgs args) { // 确定按钮进入 loading if (FeedbackRef is ConfirmRef confirmRef) { confirmRef.Config.OkButtonProps.Loading = true; await confirmRef.UpdateConfigAsync(); } await Task.Delay(1000); if (value != config) args.Cancel = true; // 校验失败,阻止关闭 else await base.OkCancelRefWithResult!.OnOk(value); // 校验通过,携带返回值 await base.OnFeedbackOkAsync(args); }对应的服务端调用(见 Modal_service_for_confirm.razor):
var options = new ConfirmOptions<string>() { Title = "Confirm", Width = 350, OnOk = (result) => { Console.WriteLine($"OnOk:{result}"); return Task.CompletedTask; }, OnCancel = (result) => { Console.WriteLine($"OnCancel:{result}"); return Task.CompletedTask; } }; await ModalService.CreateConfirmAsync(options);FAQ:为什么关闭后模板组件的 Dispose 不执行?
问题:当ModalService.CreateModalAsync<>创建的 Modal 被关闭时,为什么继承自FeedbackComponent<>的自定义组件没有执行Dispose方法?
解答:Modal 关闭后默认不会从 DOM 中移除(参见上文"状态保持"一节的容器源码逻辑),因此自定义组件的Dispose不会被调用。可以通过设置modalOptions.DestroyOnClose = true改变这一默认行为——关闭动画结束后组件即被卸载,Dispose随之触发。
这一行为与 ConfirmTemplateDemo.razor 中的注释完全对应:模板组件内重写Dispose并打印日志,配合modalConfig.DestroyOnClose = true(见 Modal_service_for_modal.razor),可以验证每次关闭都会执行Dispose。
小结
Ant Design Blazor 的 Modal 体系提供了三条互补的路径:
- 声明式
<Modal>:内嵌在页面中,通过@bind-Visible控制显隐,适合与页面强耦合的对话框; ModalService服务式调用:在任意代码位置弹出确认框或复杂对话框,通过ModalRef/ConfirmRef引用进行命令式更新与关闭,ConfirmAsync系列可直接获取用户点击结果;ConfirmService:类似 Windows MessageBox 的轻量确认框,返回精确的ConfirmResult。
三者共享同一套DialogOptionsBase配置体系,配合FeedbackComponent模板机制,足以覆盖从简单"确定/取消"到复杂表单校验弹窗的全部业务场景。如果希望深入了解实现细节,可以继续阅读 Modal.razor.cs、ModalOptions.cs、ConfirmOptions.cs 以及各组件在 site/AntDesign.Docs/Demos/Components/Modal 下的官方示例。
- 前端
- UI组件
- 设计系统
【免费下载链接】ant-design-blazor
基于 Ant Design 与 Blazor 的前端组件库。让开发者解放生产力,实现更大价值。
相关推荐
antd Modal 对话框组件完全指南:从声明式用法到静态方法与 Hooks 确认框
antd Modal 对话框组件完全指南:从声明式用法到静态方法与 Hooks 确认框 Modal(对话框)是 antd 反馈类组件中承载“二次确认与关键操作”
前端UI组件设计系统Ant Design Mobile 的 Modal 弹窗组件:声明式与指令式 API 全解析
Ant Design Mobile 的 Modal 弹窗组件:声明式与指令式 API 全解析 本文基于 ant design mobile 仓库中的 Modal
UI组件前端移动开发ant-design-mobile Modal 组件完全指南:声明式与命令式弹窗的实战用法
ant design mobile Modal 组件完全指南:声明式与命令式弹窗的实战用法 Modal(模态框)是 ant design mobile 中用于承
UI组件前端移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考