naive-ui Dialog 对话框:函数式 API 与组件式用法的完整指南

发布时间:2026/9/21 16:14:33
naive-ui Dialog 对话框:函数式 API 与组件式用法的完整指南 naive-ui Dialog 对话框函数式 API 与组件式用法的完整指南【免费下载链接】naive-uiA Vue 3 Component Library. Fairly Complete. Theme Customizable. Uses TypeScript. Fast.项目地址: https://gitcode.com/gh_mirrors/na/naive-uinaive-ui的 Dialog 对话框组件同时提供了「函数式调用」useDialog注入的dialog.warning(options)等形式与「组件式使用」n-dialog两条使用路径并允许通过n-dialog-provider集中管理所有对话框实例。本文以官方中文文档src/dialog/demos/zhCN/index.demo-entry.md为主线结合仓库源码与全部演示示例完整讲解使用前提、useDialog/useDialogReactiveListAPI、DialogOptions/DialogReactive全部配置项、组件 Props 与 Slots以及底层实现原理帮助你从“能跑通 Demo”进阶到“理解并驾驭对话框的每一个细节”。阅读本文前建议先浏览官方演示目录 src/dialog/demos/zhCN其中包含 8 个可直接运行的.demo.vue示例。使用前提把组件放进n-dialog-provider内官方文档在开篇就用警示框强调了使用函数式 Dialog 的前提如果你想使用对话框你需要把调用其方法的组件放在n-dialog-provider内部并且使用useDialog去获取 API。也就是说函数式 Dialog 依赖**依赖注入provide / inject**机制工作n-dialog-provider负责在组件树顶层注册 API任何后代组件都可以通过useDialog()获取到同一个 API 对象。典型结构如下!-- App.vue -- n-dialog-provider content / /n-dialog-providerimport { useDialog } from naive-ui import { defineComponent } from vue // content export default defineComponent({ setup() { const dialog useDialog() return { warning() { dialog.warning(options) } } } })从源码看useDialog的实现非常直接src/dialog/src/composables.tsexport function useDialog(): DialogApiInjection { const dialog inject(dialogApiInjectionKey, null) if (dialog null) { throwError(use-dialog, No outer n-dialog-provider / founded.) } return dialog }可以看到通过inject(dialogApiInjectionKey, null)从组件树上取 API如果取不到即没有外层n-dialog-provider会直接抛出错误No outer n-dialog-provider / founded.。因此凡是使用useDialog的组件都必须保证其上方存在n-dialog-provider否则运行时会报错而非静默失败。这与useMessage、useNotification等组件的使用方式一致。另外n-dialog-provider本身也接收两个可选 Props见 DialogProvider.ts名称类型说明injectionKeyString自定义注入的 key用于在特殊场景下隔离/区分多个 providertoString \| HTMLElement对话框挂载的目标位置默认跟随 teleport 逻辑useDialog API五种入口方法useDialog()返回的DialogApiInjection对象共暴露 5 个方法名称类型说明destroyAll() void销毁所有弹出的对话框create(options: DialogOptions) DialogReactive创建对话框不预设类型error(options: DialogOptions) DialogReactive调用error类型的对话框info(options: DialogOptions) DialogReactive调用info类型的对话框success(options: DialogOptions) DialogReactive调用success类型的对话框warning(options: DialogOptions) DialogReactive调用warning类型的对话框在源码实现中DialogProvider.tsinfo/success/warning/error四个类型化方法其实都是create的包装const typedApi ( [info, success, warning, error] as Array info | success | warning | error ).map(type (options: DialogOptions): DialogReactive { return create({ ...options, type }) })也就是说dialog.warning({ title: ... })等价于dialog.create({ type: warning, title: ... })只是语法糖更直观。create本身会用createId()生成唯一key把传入的options与key、destroy一起包装成reactive对象这正是后面“属性可动态修改”的基础推入dialogListRef交由 provider 渲染DialogProvider.ts。DialogOptions函数式调用时的完整配置调用dialog.create(options)时传入的options即DialogOptions。下表为官方文档列出的全部属性含默认值与引入版本名称类型默认值说明版本action() VNodeChildundefined操作区域的内容需要是渲染函数actionClassstringundefined操作区域的类名2.38.2actionStyleObject \| stringundefined操作区域的样式2.38.2autoFocusbooleantrue是否自动聚焦 Modal 第一个可聚焦的元素2.28.3blockScrollbooleantrue是否在打开时禁用 body 滚动2.28.3borderedbooleanfalse是否显示borderclassanyundefined类名2.33.0closablebooleantrue是否显示close图标closeFocusablebooleanfalse关闭按钮是否可以聚焦2.43.0closeOnEscbooleantrue是否在摁下 Esc 键的时候关闭对话框2.26.4contentstring \| (() VNodeChild)undefined对话框内容可以是渲染函数contentClassstringundefined内容的类名2.38.2contentStyleObject \| stringundefined内容的样式2.38.2draggableboolean \| { bounds?: none }false是否可拖拽2.41.0iconPlacementleft \| topleft图标的位置icon() VNodeChildundefined对话框icon需要是渲染函数loadingbooleanfalse是否显示loading状态maskClosablebooleantrue是否可以通过点击mask关闭对话框negativeButtonPropsButtonPropsundefined取消按钮的属性2.27.0negativeTextstringundefined取消按钮的文字不填对应的按钮不会出现positiveButtonPropsButtonPropsundefined确认按钮的属性2.27.0positiveTextstringundefined确认按钮的文字不填对应的按钮不会出现showIconbooleantrue是否显示iconstylestring \| Objectundefined样式titlestring \| (() VNodeChild)undefined标题可以是渲染函数titleClassstringundefined标题的类名2.38.2titleStyleObject \| stringundefined标题的样式2.38.2transformOriginmouse \| centermouse对话框动画出现的位置2.34.0typeerror \| success \| warningwarning对话框类型zIndexnumberundefinedDialog 的 z-index2.43.0onAfterEnter() voidundefined出现动画完成执行的回调2.33.0onAfterLeave() voidundefined关闭动画完成执行的回调2.33.3onClose() boolean \| Promiseboolean \| anyundefined默认行为是关闭确认框。返回false或者resolve false或者Promise被reject会避免默认行为onNegativeClick(e: MouseEvent) boolean \| Promiseboolean \| anyundefined默认行为是关闭确认框。返回false或者resolve false或者Promise被reject会避免默认行为onPositiveClick(e: MouseEvent) boolean \| Promiseboolean \| anyundefined默认行为是关闭确认框。返回false或者resolve false或者Promise被reject会避免默认行为onMaskClick() voidundefined点击蒙层后执行的回调几个容易被忽视的细节positiveText/negativeText决定按钮是否出现不填对应文字则对应按钮不会渲染。这是函数式 Dialog 最常用的“二选一/不显示按钮”控制手段。onPositiveClick等回调的“拦截”语义默认行为是关闭对话框只要回调返回false、resolve(false)或 Promise 被reject就会阻止默认的关闭行为。这一点在“异步确认”场景中非常有用详见下文异步示例。transformOrigin: mouse对话框的出现动画会以鼠标点击位置为原点展开这是 naive-ui 对话框的默认行为交互上更“跟手”可改为center让动画从屏幕中心展开。其底层通过useClicked与useClickPosition来自vooks记录点击位置见 DialogProvider.ts。draggable: { bounds?: none }自 2.41.0 起支持拖拽可通过bounds: none允许拖出可视区域边界。渲染函数型属性title、content、icon、action都支持传渲染函数() VNodeChild可以实现任意复杂的自定义内容。DialogReactive动态修改与主动销毁dialog.xxx(options)的返回值是DialogReactive它由options加两个只读字段组成DialogProvider.tsexport interface DialogReactive extends DialogOptions { readonly key: string readonly destroy: () void }DialogReactive Properties官方文档明确说明下列属性都可以被动态修改修改后对话框会实时响应。名称类型说明版本actionClassstring操作区域的类名2.38.2actionStyleObject \| string操作区域的样式2.38.2borderedboolean是否显示borderclassany类名2.33.0closableboolean是否显示close图标closeFocusableboolean关闭按钮是否可以聚焦2.43.0closeOnEscboolean是否在摁下 Esc 键的时候关闭对话框2.26.4contentstring \| (() VNodeChild)对话框内容可以是渲染函数contentClassstring内容的类名2.38.2contentStyleObject \| string内容的样式2.38.2iconPlacementleft \| top图标的位置icon() VNodeChild对话框icon需要是渲染函数loadingboolean是否显示loading状态maskClosableboolean是否可以通过点击mask关闭对话框negativeButtonPropsButtonProps取消按钮的属性2.27.0negativeTextstring取消按钮的文字不填对应的按钮不会出现positiveButtonPropsButtonProps确认按钮的属性2.27.0positiveTextstring确认按钮的文字不填对应的按钮不会出现showIconboolean是否显示iconstylestring \| Object样式titlestring \| (() VNodeChild)可以是渲染函数titleClassstring标题的类名2.38.2titleStyleObject \| string标题的样式2.38.2transformOriginmouse \| center对话框动画出现的位置2.34.0typeerror \| success \| warning对话框类型onAfterEnter() void \| undefined出现动画完成执行的回调2.33.0onAfterLeave() void \| undefined关闭动画完成执行的回调2.33.3onClose() boolean \| Promiseboolean \| any默认行为是关闭确认框。返回false或者resolve false或者Promise被reject会避免默认行为onEsc() void焦点在 dialog 内部时按下 Esc 键的回调2.32.0onNegativeClick(e: MouseEvent) boolean \| Promiseboolean \| any默认行为是关闭确认框。返回false或者resolve false或者Promise被reject会避免默认行为onPositiveClick(e: MouseEvent) boolean \| Promiseboolean \| any默认行为是关闭确认框。返回false或者resolve false或者Promise被reject会避免默认行为相比DialogOptionsDialogReactive额外暴露了onEsc回调2.32.0用于监听焦点在对话框内部时按下 Esc 键的事件onAfterEnter/onAfterLeave的类型标注为() void | undefined。DialogReactive Methods名称类型说明destroy()关闭Dialog在源码中destroy被实现为调用对应对话框实例的hide()方法DialogProvider.tsdestroy: () { dialogInstRefs[n-dialog-${key}]?.hide() }而destroyAll()则遍历所有实例统一调用hide()DialogProvider.ts。对话框关闭动画结束后handleAfterLeave会把对应实例从dialogListRef中移除DialogProvider.ts。组件式用法n-dialog Props 与 Slots除了函数式调用n-dialog也可以像普通组件一样直接写在模板中官方演示 use-component.demo.vue 即为此用法template n-dialog title确认 content你确定 negative-text不确认 positive-text确认 positive-clickhandlePositiveClick negative-clickhandleNegativeClick / /templateDialog Props名称类型默认值说明版本action-classstringundefined操作区域的类名2.38.2action-styleObject \| stringundefined操作区域的样式2.38.2borderedbooleanfalse是否显示borderclosablebooleantrue是否显示close图标close-focusablebooleanfalse关闭按钮是否可以聚焦2.43.0contentstring \| (() VNodeChild)undefined对话框内容可以是渲染函数content-classstringundefined内容的类名2.38.2content-styleObject \| stringundefined内容的样式2.38.2icon-placementleft \| topleft图标放置的位置icon() VNodeChildundefined需要是渲染函数loadingbooleanfalse是否显示loading状态negative-button-propsButtonPropsundefined取消按钮的属性2.27.0negative-textstringundefined取消按钮的文字不填对应的按钮不会出现positive-button-propsButtonPropsundefined确认按钮的属性2.27.0positive-textstringundefined确认按钮的文字不填对应的按钮不会出现show-iconbooleantrue是否显示icontitlestring \| (() VNodeChild)undefined对话框标题可以是渲染函数title-classstringundefined标题的类名2.38.2title-styleObject \| stringundefined标题的样式2.38.2typeerror \| success \| warning \| infowarning对话框类型on-close() voidundefined点击关闭时执行的回调函数on-negative-click(e: MouseEvent) voidundefined执行negative时执行的回调函数on-positive-click(e: MouseEvent) voidundefined执行positive时执行的回调函数注意两点差异组件 Props 采用kebab-case命名action-class、positive-text等组件模式下type支持四种值比DialogOptions多一个info且事件回调类型为() void不参与关闭拦截逻辑拦截能力仅存在于函数式 API 中。Dialog Slots名称参数说明版本action()action内容default()对话框内容header()header内容icon()icon内容close()close内容2.36.0官方演示逐例解读官方中文文档在“演示”一节中按顺序引入了 8 个示例src/dialog/demos/zhCN下面逐一解读其核心要点。1. 基础用法basic.demo.vue通过dialog.warning / success / error分别触发三种类型的对话框演示了title、content、positiveText、negativeText、draggable及两个点击回调的常规组合dialog.warning({ title: 警告, content: 你确定, positiveText: 确定, negativeText: 不确定, draggable: true, onPositiveClick: () message.success(确定), onNegativeClick: () message.error(不确定) })这是日常“删除确认”“操作确认”弹窗的最典型写法类型图标与配色 标题 内容 确认/取消文案 回调。2. 异步async.demo.vue演示了onPositiveClick返回 Promise 时对话框会保持打开并进入 loading 状态直到 Promise resolve 才关闭。示例中点击确认后依次展示“倒计时 3 秒 → 2 秒 → 1 秒 → 0 秒”期间通过修改响应式属性d.loading和d.content实时驱动 UIconst d dialog.success({ title: 异步, content: 点击倒计时 3 秒, positiveText: 确认, onPositiveClick: () { d.loading true return new Promise((resolve) { sleep() .then(() { d.content countDown(2); return sleep() }) .then(() { d.content countDown(1); return sleep() }) .then(() { d.content countDown(0) }) .then(resolve) }) } })这正是前面提到的“回调拦截 动态属性”两大能力的组合应用回调返回 Promise关闭行为被挂起d.loading控制确认按钮 loadingd.content实时更新内容。3. 使用组件use-component.demo.vue直接使用n-dialog组件通过positive-click/negative-click事件与negative-text/positive-textProps 完成交互适合把对话框作为页面内固定区块而非浮层使用的场景。4. 点击遮罩mask.demo.vue演示maskClosable: false禁止点击遮罩关闭同时通过onMaskClick在点击遮罩时给出提示、通过onEsc监听键盘 Escdialog.success({ title: 关闭, content: 你确定, positiveText: 确定, negativeText: 不确定, maskClosable: false, onMaskClick: () message.success(不能关闭), onEsc: () message.success(通过 esc 关闭) })适合“强确认”场景如不可撤销的删除操作强制用户只能通过明确按钮关闭。5. 自定义 Actionaction.demo.vue演示title、content、action三个渲染函数属性任意输出自定义 VNodedialog.warning({ title: 使用渲染函数, content: () Content, action: () Action })当默认的确认/取消按钮无法满足需求例如需要嵌入表单、多按钮或自定义布局时可完全接管action区域的内容。6. 访问全部 Dialog 实例use-dialog-reactive-list.demo.vue使用useDialogReactiveList()获取当前n-dialog-provider下全部对话框实例的响应式数组直接渲染数量const dialogReactiveList useDialogReactiveList() // 模板中目前页面中共有 {{ dialogReactiveList.length }} 个对话框。useDialogReactiveList的实现同样基于依赖注入composables.ts返回的是Refreadonly DialogReactive[]由于 provider 内部维护的是同一个dialogListRef列表会随对话框的创建与销毁自动增删。官方文档给出的类型签名为() Refreadonly DialogReactive[]7. Focus debugfocus-debug.demo.vue该示例通过渲染函数在content中放置两个NTimePicker用于验证对话框打开后的焦点管理行为配合autoFocus、closeFocusable等配置调试键盘可达性。8. RTL debugrtl-debug.demo.vue用于验证n-config-provider开启 RTL从右到左布局后对话框的样式表现样式定义可参见 src/dialog/src/styles/rtl.cssr.ts。底层原理DialogProvider 的完整工作流综合 DialogProvider.ts 与 composables.ts函数式 Dialog 的完整调用链可以概括为注册NDialogProvider.setup中创建dialogListRef、dialogInstRefs并把 API 对象与响应式列表通过三个 injection key 注入组件树dialogApiInjectionKey、dialogProviderInjectionKey、dialogReactiveListInjectionKey见 context.ts 与 DialogProvider.ts。创建调用dialog.warning(options)→create({ ...options, type })→ 生成key、包装成reactive对象、push进dialogListRef。渲染provider 的render()遍历dialogList为每个实例渲染一个NDialogEnvironmentDialogEnvironment.tsx并把destroy与style剥离、以internalStyle/internalKey传入每个实例通过ref回调登记到dialogInstRefs以便destroy/destroyAll找到它。销毁destroy()/destroyAll()调用hide()播放关闭动画动画结束后handleAfterLeave将实例从列表移除实现“创建即入列、销毁即出列”的完整生命周期。函数式 Dialog 的核心优势由此体现调用方无需维护组件挂载状态所有实例由 provider 统一管理并且由于DialogReactive是响应式对象调用方持有引用后可以随时动态修改任意属性——这是组件式n-dialog难以直接实现的“远程控制”能力。在测试层面仓库提供了 src/dialog/tests/Dialog.spec.tsx 覆盖交互行为以及 server.spec.tsx 验证服务端渲染SSR场景下的稳定性对话框的明暗主题变量定义在 src/dialog/styles/light.ts 与 src/dialog/styles/dark.ts可通过主题覆盖机制统一定制。结语naive-ui 的 Dialog 组件在设计上提供了“双轨制”使用方式函数式 APIuseDialogDialogOptions适合需要程序化控制、异步确认、动态更新的场景组件式n-dialog适合在模板中静态声明、以事件驱动交互的场景。官方中文文档src/dialog/demos/zhCN/index.demo-entry.md中列出的全部 API 表格与 8 个演示示例覆盖了从基础确认框到异步倒计时、从遮罩控制到自定义渲染函数的完整能力图谱结合 DialogProvider.ts 的实现可以清晰理解其依赖注入、响应式实例管理与生命周期清理机制从而在真实项目中得心应手地使用与调试。【免费下载链接】naive-uiA Vue 3 Component Library. Fairly Complete. Theme Customizable. Uses TypeScript. Fast.项目地址: https://gitcode.com/gh_mirrors/na/naive-ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考