如何开发支持返回Promise的Vue Dialog对话框插件?
基于Promise的Vue Dialog对话框插件实现方法
核心实现逻辑
Dialog插件的核心是调用show()方法时返回一个Promise实例,将Promise的resolve方法暂存在组件内部状态中,用户点击确认/取消按钮时,调用该resolve方法传入对应布尔值即可实现需求。
完整实现步骤
我们以Vue3为例,同时补充Vue2的适配方案:
1. 编写Dialog基础组件(ConfirmDialog.vue)
<template> <div v-if="visible" class="dialog-mask" @click.self="onCancel"> <div class="dialog-content"> <p>确认执行该操作吗?</p> <div class="dialog-btns"> <button @click="onCancel">取消</button> <button class="confirm-btn" @click="onConfirm">确认</button> </div> </div> </div> </template> <script setup> import { ref } from 'vue' const visible = ref(false) let resolveFn = null // 对外暴露的show方法,返回Promise const show = () => { // 避免重复弹出未处理的弹窗 if (resolveFn) { resolveFn(false) } visible.value = true return new Promise((resolve) => { resolveFn = resolve }) } const onConfirm = () => { visible.value = false resolveFn(true) resolveFn = null } const onCancel = () => { visible.value = false resolveFn(false) resolveFn = null } // 暴露方法给外部调用 defineExpose({ show }) </script> <style scoped> .dialog-mask { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; } .dialog-content { background: #fff; padding: 20px; border-radius: 4px; min-width: 300px; } .dialog-btns { display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px; } .confirm-btn { background: #409eff; color: #fff; border: none; padding: 4px 12px; border-radius: 4px; } </style>
效果示意图:
2. 编写插件注册逻辑(dialogPlugin.js)
import { createApp } from 'vue' import ConfirmDialog from './ConfirmDialog.vue' const dialogPlugin = { install(app) { // 创建组件实例并挂载到body const mountNode = document.createElement('div') document.body.appendChild(mountNode) const dialogInstance = createApp(ConfirmDialog).mount(mountNode) // 挂载到全局属性,组件内可以通过this.$dialog调用 app.config.globalProperties.$dialog = dialogInstance // 兼容组合式API直接引入调用 app.provide('$dialog', dialogInstance) } } export default dialogPlugin
3. 全局注册插件
在main.js中引入注册:
import { createApp } from 'vue' import App from './App.vue' import dialogPlugin from './dialogPlugin' const app = createApp(App) app.use(dialogPlugin) app.mount('#app')
4. 业务中使用
和需求描述的调用方式完全一致:
async onDel(item) { const confirm = await this.$dialog.show() if (confirm) { this.delete(item) } }
Vue2适配调整
Vue2版本仅需调整插件注册逻辑和组件写法即可:
- 组件改为选项式API,将show方法、visible、resolveFn放在data和methods中
- 插件注册时使用
Vue.extend创建实例:
import Vue from 'vue' import ConfirmDialog from './ConfirmDialog.vue' const DialogConstructor = Vue.extend(ConfirmDialog) const dialogInstance = new DialogConstructor() dialogInstance.$mount(document.createElement('div')) document.body.appendChild(dialogInstance.$el) Vue.prototype.$dialog = dialogInstance
内容的提问来源于stack exchange,提问作者morteza mortezaie
相关产品推荐
相关产品推荐

