
vue-vben-admin 弹窗组件 Vben Alert 深度指南alert、confirm、prompt 函数式调用与源码实现【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-adminVben Alert是 vue-vben-admin 中基于 JavaScript 驱动的轻量级弹窗体系通过alert、confirm、prompt三个函数即可在任意业务代码中弹出对话框而无需在模板中显式维护弹窗组件。本文以官方文档 vben-alert.md 为主线结合popup-ui包的源码与官方 Demo完整讲解三种弹窗的调用方式、AlertProps/PromptProps全部参数、useAlertContext上下文用法以及底层 Promise 化封装的实现原理帮助你写出可复制的弹窗代码并理解其工作机制。Vben Alert 是什么Alert提供了一组轻量级、由 JavaScript 驱动的对话框用于完成简单的alert仅确认、confirm确认/取消和prompt用户输入三类交互。它不同于传统在模板中放一个Modalv-model的写法——调用方只需要写一行函数返回的 Promise 让结果处理变得非常直观。在仓库中Vben Alert 的实现集中在 packages/core/ui-kit/popup-ui/src/alert/ 目录alert.ts定义AlertProps、PromptProps、IconType、BeforeCloseScope等核心类型以及useAlertContextAlertBuilder.ts实现vbenAlert、vbenConfirm、vbenPrompt三个函数式入口与clearAllAlertsalert.vue基于 shadcn-uiAlertDialog封装的弹窗视图组件index.ts对外统一导出。从 index.ts 可以看到对外暴露的完整 APIexport type { AlertProps, BeforeCloseScope, IconType, PromptProps } from ./alert; export { useAlertContext } from ./alert; export { default as Alert } from ./alert.vue; export { vbenAlert as alert, clearAllAlerts, vbenConfirm as confirm, vbenPrompt as prompt } from ./AlertBuilder;也就是说在业务代码中你通常直接使用alert、confirm、prompt三个别名函数由vben/common-ui汇总导出官方 Demo 中均以import { alert, confirm, prompt, useAlertContext, VbenButton } from vben/common-ui方式引入。基本用法alert单确认按钮弹窗alert用于告知场景只有一个确认按钮。最简单的调用是直接传入字符串作为内容官方 Demo 见 docs/src/demos/vben-alert/alert/index.vueimport { alert, VbenButton } from vben/common-ui; function showAlert() { alert(This is an alert message); }传入对象可以配置图标function showIconAlert() { alert({ content: This is an alert message with icon, icon: success, }); }内容不仅限于字符串还支持通过h()渲染自定义组件import { h } from vue; import { Result } from antdv-next; function showCustomAlert() { alert({ buttonAlign: center, content: h(Result, { status: success, subTitle: 已成功创建订单。订单ID2017182818828182881, title: 操作成功, }), }); }confirm确认/取消交互confirm提供确认 取消两个按钮返回的 Promise 在确认时resolve、取消时reject因此可以用.then/.catch分流结果官方 Demo 见 docs/src/demos/vben-alert/confirm/index.vueimport { alert, confirm, VbenButton } from vben/common-ui; function showConfirm() { confirm(This is an alert message) .then(() { alert(Confirmed); }) .catch(() { alert(Canceled); }); }带图标、自定义按钮文案、以及自定义footer与按钮同容器可用于追加不再提示等附加内容import { h, ref } from vue; import { Checkbox, message } from antdv-next; function showfooterConfirm() { const checked ref(false); confirm({ cancelText: 不要虾扯蛋, confirmText: 是的我们都是NPC, content: 刚才发生的事情为什么我似乎早就经历过一般……, footer: () h(Checkbox, { checked: checked.value, class: flex-1, onUpdate:checked: (v) (checked.value v), }, 不再提示), icon: question, title: 未解之谜, }).then(() { if (checked.value) { message.success(我不会再拿这个问题烦你了); } else { message.info(下次还要继续问你哟); } }); }异步确认通过beforeClose钩子在关闭前执行异步操作只有返回非false才会真正关闭function showAsyncConfirm() { confirm({ beforeClose({ isConfirm }) { if (isConfirm) { // 这里可以执行一些异步操作。如果最终返回了false将阻止关闭弹窗 return new Promise((resolve) setTimeout(resolve, 2000)); } }, content: This is an alert message with async confirm, icon: success, }).then(() { alert(Confirmed); }); }prompt获取用户输入prompt在确认/取消的基础上内置了一个输入组件确认后 Promise 会resolve出用户输入的值官方 Demo 见 docs/src/demos/vben-alert/prompt/index.vueimport { alert, prompt, useAlertContext, VbenButton } from vben/common-ui; function showPrompt() { prompt({ content: 请输入一些东西 }) .then((val) { alert(已收到你的输入${val}); }) .catch(() { alert(Canceled); }); }通过component指定任意输入组件默认是Input并用modelPropName指定值绑定的属性名。下面的例子在组件函数内调用useAlertContext()拿到doConfirm实现输入框内按回车触发确认import { h } from vue; import { Input } from antdv-next; import { BadgeJapaneseYen } from lucide/vue; function showSlotsPrompt() { prompt({ component: () { // 获取弹窗上下文。注意只能在setup或者函数式组件中调用 const { doConfirm } useAlertContext(); return h(Input, { onKeydown(e: KeyboardEvent) { if (e.key Enter) { e.preventDefault(); // 调用弹窗提供的确认方法 doConfirm(); } }, placeholder: 请输入, prefix: 充值金额, type: number, }, { addonAfter: () h(BadgeJapaneseYen), }); }, content: ……在输入框中按下回车键会触发确认操作。, icon: question, modelPropName: value, }).then((val) { if (val) alert(你输入的是${val}); }); }传入已有组件实例如Select并通过componentProps传参。官方 Demo 特别指出弹窗会设置 body 的pointer-events: none这会阻断下拉浮层点击因此下拉类组件需要显式声明popupClassName: pointer-events-autoimport { Select } from antdv-next; function showSelectPrompt() { prompt({ component: Select, componentProps: { options: [ { label: Option A, value: Option A }, { label: Option B, value: Option B }, { label: Option C, value: Option C }, ], placeholder: 请选择, // 弹窗会设置body的pointer-events为none这会影响到下拉框的点击事件 popupClassName: pointer-events-auto, }, content: 此弹窗演示了如何使用component传递自定义组件, icon: question, modelPropName: value, }).then((val) { if (val) { alert(你选择了${val}); } }); }prompt同样支持异步校验在beforeClose的scope中可通过scope.value拿到当前输入值返回false阻止关闭function showAsyncPrompt() { prompt({ async beforeClose(scope) { if (scope.isConfirm) { if (scope.value) { // 模拟异步操作如果不成功可以返回false await sleep(2000); } else { alert(请选择一个选项); return false; } } }, component: RadioGroup, componentProps: { class: flex flex-col, options: [ { label: Option 1, value: option1 }, { label: Option 2, value: option2 }, { label: Option 3, value: option3 }, ], }, content: 选择一个选项后再点击[确认], icon: question, modelPropName: value, }).then((val) { alert(${val} 已设置。); }); }函数签名与重载从源码 AlertBuilder.ts 可以看到vbenAlert支持三种重载形式export function vbenAlert(options: AlertProps): Promisevoid; export function vbenAlert(message: string, options?: PartialAlertProps): Promisevoid; export function vbenAlert(message: string, title?: string, options?: PartialAlertProps): Promisevoid;vbenConfirm具有同样的三种重载见 AlertBuilder.ts其内部逻辑是若传入的是字符串则自动补上{ showCancel: true }默认属性再委托给vbenAlert完成渲染vbenPrompt则统一接收PromptPropsT对象并最终调用vbenConfirm。因此alert(msg)、alert(msg, 标题)、alert({ ... })均可confirm(msg)自动带取消按钮prompt({ ... })返回值是PromiseT | undefined。核心类型详解文档给出的核心类型定义与源码 alert.ts 完全一致export type IconType error | info | question | success | warning; export type BeforeCloseScope { isConfirm: boolean; }; export type AlertProps { beforeClose?: ( scope: BeforeCloseScope, ) boolean | Promiseboolean | undefined | undefined; bordered?: boolean; buttonAlign?: center | end | start; cancelText?: string; centered?: boolean; confirmText?: string; containerClass?: string; content: Component | string; contentClass?: string; contentMasking?: boolean; footer?: Component | string; icon?: Component | IconType; overlayBlur?: number; showCancel?: boolean; title?: string; }; export type PromptPropsT any { beforeClose?: (scope: { isConfirm: boolean; value: T | undefined; }) boolean | Promiseboolean | undefined | undefined; component?: Component; componentProps?: Recordableany; componentSlots?: | (() any) | Recordableunknown | VNode | VNodeArrayChildren; defaultValue?: T; modelPropName?: string; } OmitAlertProps, beforeClose;AlertProps 参数一览参数类型默认值说明beforeClose(scope: BeforeCloseScope) boolean \| Promiseboolean \| undefined \| undefined-关闭前的回调返回false则终止关闭scope.isConfirm表示本次关闭是否由确认触发borderedbooleantrue是否显示边框关闭边框时改用shadow-3xl阴影见 alert.vuebuttonAligncenter \| end \| startend底部按钮对齐方式cancelTextstring国际化$t(cancel)取消按钮文案centeredbooleantrue是否居中显示confirmTextstring国际化$t(confirm)确认按钮文案containerClassstring-弹窗容器的额外样式类contentComponent \| string-必填弹窗提示内容支持字符串或组件contentClassstring-弹窗内容区域的额外样式类contentMaskingboolean-执行beforeClose回调期间在内容区域显示一个 loading 遮罩escapeKeyClosebooleantrue按下 Esc 是否关闭弹窗源码额外提供的属性受全局globalEscapeShortcutKey配置共同控制footerComponent \| string-弹窗底部内容与按钮处于同一容器iconComponent \| IconType-弹窗图标位于标题之前可用内置类型或自定义组件overlayBlurnumber-弹窗遮罩的模糊程度showCancelbooleanfalsealert/trueconfirm是否显示取消按钮titlestring$t(prompt)弹窗标题其中部分默认值定义在 alert.vueconst props withDefaults(definePropsAlertProps(), { bordered: true, buttonAlign: end, centered: true, escapeKeyClose: true, });标题默认值在 AlertBuilder.ts 中补充为$t.value(prompt)即提示类国际化文案按钮文案的兜底则来自 alert.vue 中的cancelText || $t(cancel)与confirmText || $t(confirm)这也解释了为什么系统语言切换后按钮文字会自动跟随。PromptProps 专属参数参数类型默认值说明componentComponent内置Input用于接收用户输入的组件componentPropsRecordableany-输入组件的属性componentSlots() any \| Recordableunknown \| VNode \| VNodeArrayChildren-输入组件的插槽defaultValueTundefined输入组件的默认值modelPropNamestringmodelValue输入组件的值属性名如 antdv 的Input用valuebeforeClose(scope: { isConfirm; value }) ...-与AlertProps不同scope中额外携带当前输入值value注意PromptProps是OmitAlertProps, beforeClose与上述字段的交集因为prompt的beforeClose签名中scope多了value字段其余AlertProps参数content、icon、title等同样适用。内置 IconType 与图标映射icon传入字符串时alert.vue 会将其映射为对应图标组件并套用主题色error→CircleX颜色hsl(var(--destructive))info→Info颜色hsl(var(--info))question→CircleHelpsuccess→CircleCheckBig颜色hsl(var(--success))warning→CircleAlert颜色hsl(var(--warning))useAlertContext在自定义内容中操作弹窗当content、footer或icon通过自定义组件渲染时如果需要在组件内部主动触发确认/取消例如上文的回车确认、自定义表单中的确定按钮可以调用useAlertContext()获取当前弹窗的动作方法说明类型doConfirm触发确认操作() voiddoCancel触发取消操作() voidimport { useAlertContext } from vben/common-ui; const { doConfirm, doCancel } useAlertContext();从源码看该上下文由 alert.ts 基于 shadcn-ui 的createContext提供export const [injectAlertContext, provideAlertContext] createContextAlertContext(VbenAlertContext); export function useAlertContext() { const context injectAlertContext(); if (!context) { throw new Error(useAlertContext must be used within an AlertProvider); } return context; }而上下文的生产方是 alert.vuedoConfirm/doCancel内部会先更新isConfirm标记再触发handleOpenChange(false)走关闭流程。使用限制官方 Demo 注释中明确说明useAlertContext只能在setup或函数式组件中调用。这也对应了文档中的场景——它必须运行在由弹窗内容content/footer/icon所渲染的组件内部因为上下文是通过组件树provide/inject传递的若在组件外调用injectAlertContext会取到undefined并抛出useAlertContext must be used within an AlertProvider错误。底层实现原理函数调用如何变成弹窗Promise 化封装vbenAlert的核心流程AlertBuilder.ts如下归一化参数字符串会被包装为{ content: arg0 }第二、三个参数标题字符串或配置对象会合并进options创建一个div容器并追加到document.body通过h(Alert, props)创建 VNode再用render(vnode, container)将其挂载到容器上实现无模板声明的动态渲染监听onClosed(isConfirm)关闭时从alerts数组移除实例、render(null, container)卸载组件、从 DOM 中移除容器恢复页面到打开前的状态最后按用户操作结果resolve()或reject(new Error(dialog cancelled))。因此.then对应确认、.catch对应取消/关闭这是整个函数式 API 的语义根基。beforeClose 关闭拦截流程alert.vue 中的handleOpenChange是关闭拦截的核心async function handleOpenChange(val: boolean) { await nextTick(); // 等待标记isConfirm状态 if (!val props.beforeClose) { loading.value true; try { const res await props.beforeClose({ isConfirm: isConfirm.value }); if (res ! false) { open.value false; } } finally { loading.value false; } } else { open.value val; } }当弹窗要关闭val false且配置了beforeClose时先置loading true执行回调只有回调结果! false才真正关闭。结合contentMasking: true时会在内容区域渲染VbenLoading遮罩alert.vue这就是异步确认期间按钮禁用 内容遮罩的实现来源。Esc 键行为onEscapeKeyDownalert.vue中只有当组件参数escapeKeyClose与全局偏好globalEscapeShortcutKey都为false时才阻止默认关闭行为即两者任一为true都允许按 Esc 关闭。prompt 的输入管理vbenPromptAlertBuilder.ts的关键实现用modelValueref 保存输入值modelPropName默认modelValue渲染输入组件时绑定[modelPropName]: modelValue.value和onUpdate:${modelPropName}回调实现双向同步beforeClose被包装把scope.value modelValue.value注入给用户回调onOpened在弹窗打开后自动聚焦输入组件优先调用组件exposed.focus否则回退到原生el.focus或查询input, select, textarea, button聚焦保证用户打开即可输入最后await vbenConfirm(props)复用确认弹窗渲染确认后返回modelValue.value。批量清理clearAllAlertsAlertBuilder.ts遍历内部维护的alerts数组逐个render(null, container)卸载并移除 DOM 容器可用于路由切换或登出时强制关闭所有弹窗。实践建议校验类交互优先用promptbeforeClose在回调里校验scope.value不合法就return false同时用alert(请选择一个选项)提示避免打开第二个弹窗造成嵌套下拉/日期等浮层组件需要pointer-events-auto因为弹窗会对 body 设置pointer-events: none像Select的popupClassName必须显式声明才能正常点击选项自定义内容中需要控制弹窗时用useAlertContext注意调用位置必须在setup/函数式组件内回车提交、自定义表单确定都是典型场景异步确认记得配contentMaskingvbenPrompt已默认开启alert/confirm手动传contentMasking: true可以在异步beforeClose期间给出视觉反馈并防止重复点击需要批量关闭时调用clearAllAlerts()该函数由 index.ts 一并导出。更多资源官方文档docs/src/en/components/common-ui/vben-alert.md中文文档docs/src/components/common-ui/vben-alert.md官方 Demoalert、confirm、prompt源码实现alert.ts、AlertBuilder.ts、alert.vue、index.ts测试用例alert-builder.test.ts、alert.test.ts【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考