You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何开发支持返回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版本仅需调整插件注册逻辑和组件写法即可:

  1. 组件改为选项式API,将show方法、visible、resolveFn放在data和methods中
  2. 插件注册时使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 03:24:02