DialogService 单例通过全局唯一实例+provide/inject 实现:main.ts 创建一次并 provide,子组件 inject 获取同一引用;open() 返回 Promise 支持 await;支持动态挂载任意组件。

Provide 本身不直接创建单例,但配合 provide / inject 与一个**全局唯一的状态管理实例**,就能实现真正意义上的全局弹窗服务单例——所有组件调用的都是同一个弹窗控制器。
核心思路:把弹窗逻辑封装成可复用的服务类
不要在每个组件里重复写 showModal 或维护 visible 状态。而是定义一个类(如 DialogService),内部用 ref 或 reactive 管理弹窗数据,并暴露 open()、close()、confirm() 等方法。
- 该类实例只在应用初始化时创建一次(例如在
main.ts中) - 通过
provide('dialogService', dialogService)注入到根组件 - 任意深层子组件用
inject('dialogService')获取同一引用
避免常见陷阱:别在 setup 里重复 new 实例
如果在某个组件的 setup() 中又 new DialogService(),那就破坏了单例。务必确保:
- 服务实例创建时机唯一(推荐:App 组件
setup或main.ts) - provide 的 key 是字符串或 Symbol(推荐 Symbol,避免命名冲突)
- inject 时使用完全相同的 key,且建议加默认值提示未正确 provide
支持异步交互:让 open() 返回 Promise
真实场景中,常需要“用户点击确定后继续执行”。可在服务类中用 Promise + resolve 控制流:
-
open(options)内部返回new Promise((resolve) => { ... }) - 弹窗组件触发确认时调用
this.resolve(true),取消时调用this.resolve(false) - 调用方可直接
await dialogService.open({...}),语义清晰
进阶:动态挂载弹窗组件,解耦 UI 与逻辑
弹窗内容不写死,而是支持传入任意组件(如 { component: ConfirmDialog, props: { title: '删除?' } }):
- 服务类中用
createApp动态创建弹窗实例 - 用
render函数或h渲染传入的组件 - 挂载到
document.body,并监听销毁时机释放资源 - 这样业务组件完全不感知 DOM 操作,只专注逻辑和配置
不复杂但容易忽略:单例的本质是引用一致,Provide 是桥梁,服务类才是核心载体。

















