将 $confirm 对话框改为 a-modal 实现的通用技术方案

背景

在 Vue 项目中,Ant Design Vue 的 this.$confirm() 是一个便捷的弹窗 API,但在复杂的场景下,它存在一些局限性:

  • 可定制性有限,只能通过配置项调整
  • 使用 JSX 语法,与 Vue 模板风格不一致
  • 样式控制受限于 API
  • 调试不够直观

本文介绍如何将 $confirm 改为使用 <a-modal> 组件实现,提供更好的开发体验和可维护性。

原代码示例:

适用场景:例如在提交数据之前让用户二次确认。

js 复制代码
beforeSubmit() {
  return new Promise((resolve) => {
    this.$confirm({
      title: '确认',
      content: '确定要执行此操作吗?',
      okText: '确定',
      cancelText: '取消',
      onOk() {
        resolve(true)
      },
      onCancel() {
        resolve(false)
      }
    })
  })
},
async submit() {
  if (await checkSomething()) {
    // 提交数据
  }
}

技术方案

核心思路

  1. 保持接口不变: 保持原有的 Promise 接口,确保调用方无需修改
  2. 状态管理: 使用组件状态控制弹窗显示和数据
  3. 自定义渲染: 使用 Vue 模板替代 JSX
  4. 事件封装: 通过保存 Promise resolve 来维持原有的异步特性

实现步骤

步骤 1: 添加状态变量

javascript 复制代码
data() {
  return {
    // 弹窗显示状态
    confirmModalVisible: false,
    // Promise resolve 引用
    confirmModalResolve: null,
  }
}

步骤 2: 在模板中添加 a-modal

html 复制代码
<template>
  <div>
    <!-- 你的其他内容 -->
    
    <!-- 确认弹窗 -->
    <a-modal
      title="确认操作"
      :visible="confirmModalVisible"
      :width="500"
      @ok="handleConfirmModalOk"
      @cancel="handleConfirmModalCancel"
    >
      <!-- 弹窗内容 -->
      <div class="modal-content">
        <!-- 警告提示 -->
        确定要执行此操作吗?
      </div>
    </a-modal>
  </div>
</template>

步骤 3: 封装弹窗方法

javascript 复制代码
methods: {
  // 确认按钮点击
  handleConfirmModalOk() {
    if (this.confirmModalResolve) {
      this.confirmModalResolve(true)
    }
    this.closeConfirmModal()
  },
  
  // 取消按钮点击
  handleConfirmModalCancel() {
    if (this.confirmModalResolve) {
      this.confirmModalResolve(false)
    }
    this.closeConfirmModal()
  },
  
  // 关闭弹窗并清理
  closeConfirmModal() {
    this.confirmModalVisible = false
    this.confirmModalResolve = null
  }
}

步骤 4: 替换原有的 $confirm 调用

原代码:

javascript 复制代码
beforeSubmit() {
  return new Promise((resolve) => {
    this.$confirm({
      title: '确认',
      content: '确定要执行此操作吗?',
      okText: '确定',
      cancelText: '取消',
      onOk() {
        resolve(true)
      },
      onCancel() {
        resolve(false)
      }
    })
  })
},
async submit() {
  if (await checkSomething()) {
    // 提交数据
  }
}

新代码:

javascript 复制代码
beforeSubmit() {
  return new Promise((resolve) => {
      this.confirmModalResolve = resolve;
      this.confirmModalVisible = true;
    });
}
async submit() {
  if (await checkSomething()) {
    // 提交数据
  }
}

方案对比

特性 $confirm a-modal
可定制性 ⭐⭐ 有限 ⭐⭐⭐⭐⭐ 完全灵活
模板语法 JSX Vue 模板
样式控制 ⭐⭐ ⭐⭐⭐⭐⭐
调试体验 ⭐⭐ ⭐⭐⭐⭐⭐
代码组织 集中在一处 分离清晰
学习曲线 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐

最佳实践

  1. 封装通用组件: 可以将这个模式进一步封装成通用的确认弹窗组件,供整个项目使用
  2. 保持接口稳定: 始终保持 Promise 接口,避免大面积修改调用方
  3. 状态清理: 弹窗关闭时一定要清理相关状态,避免内存泄漏
  4. 样式复用: 将弹窗的通用样式提取到全局样式或组件中
  5. 类型安全: 如果使用 TypeScript,可以为 confirmModalData 定义接口

完整代码示例

vue 复制代码
<template>
  <div>
    <a-button @click="testConfirm">测试确认弹窗</a-button>
    
    <a-modal
      title="确认操作"
      :visible="confirmModalVisible"
      :width="500"
      :footer="null"
      @cancel="handleConfirmModalCancel"
    >
      <div class="modal-content">
        <a-alert 
          v-if="confirmModalData?.warning"
          :description="confirmModalData.warning"
          type="info"
        />
        <div v-if="confirmModalData?.content" class="modal-body">
          {{ confirmModalData.content }}
        </div>
      </div>
      
      <div class="modal-footer">
        <a-button @click="handleConfirmModalCancel">
          {{ confirmModalData?.cancelText || '取消' }}
        </a-button>
        <a-button type="primary" @click="handleConfirmModalOk">
          {{ confirmModalData?.okText || '确定' }}
        </a-button>
      </div>
    </a-modal>
  </div>
</template>

<script>
export default {
  data() {
    return {
      confirmModalVisible: false,
      confirmModalData: null,
      confirmModalResolve: null
    }
  },
  methods: {
    showConfirm(options) {
      return new Promise((resolve) => {
        this.confirmModalData = options
        this.confirmModalResolve = resolve
        this.confirmModalVisible = true
      })
    },
    
    handleConfirmModalOk() {
      this.confirmModalResolve?.(true)
      this.closeConfirmModal()
    },
    
    handleConfirmModalCancel() {
      this.confirmModalResolve?.(false)
      this.closeConfirmModal()
    },
    
    closeConfirmModal() {
      this.confirmModalVisible = false
      this.confirmModalResolve = null
      this.confirmModalData = null
    },
    
    async testConfirm() {
      const result = await this.showConfirm({
        warning: '此操作将删除数据',
        content: '确定要继续吗?',
        okText: '确认删除',
        cancelText: '取消'
      })
      
      if (result) {
        console.log('用户确认了操作')
      } else {
        console.log('用户取消了操作')
      }
    }
  }
}
</script>

<style lang="less" scoped>
.modal-content {
  max-height: 60vh;
  overflow: auto;
}

.modal-body {
  margin-top: 16px;
}
</style>

<style lang="less">
.modal-footer {
  display: flex;
  justify-content: flex-end;
  padding: 16px;
  border-top: 1px solid #f0f0f0;
  margin-top: 16px;
  
  button {
    margin-left: 8px;
  }
}
</style>

总结

$confirm 改为 <a-modal> 是一个提升代码可维护性和可定制性的好做法。核心要点是:

  1. ✅ 使用 Promise 保持接口不变
  2. ✅ 使用状态管理弹窗显示
  3. ✅ 使用 Vue 模板替代 JSX
  4. ✅ 自定义 footer 获得完全控制
  5. ✅ 及时清理状态避免内存问题

这种模式可以广泛应用于 Vue + Ant Design Vue 的项目中,希望对你有所帮助!

相关推荐
zhangyao9403308 小时前
开发pc端时,表格的高度怎么设置才能铺满页面
前端·javascript·elementui
XinZong8 小时前
实测OpenClaw虾淘:全民工具AI时代,冷门非工具类的Skill还能出圈吗?
javascript
烛衔溟8 小时前
TypeScript 类的类型 —— 作为类型使用
javascript·ubuntu·typescript
之歆9 小时前
Day16_JavaScript 轮播图与事件工程实战(下篇)
服务器·开发语言·前端·javascript·网络·性能优化
kyriewen9 小时前
我关掉了Copilot:因为我写的代码出现在了别人的建议里
前端·javascript·ai编程
SmartRadio10 小时前
STM32WLE5 LoRa Smart TDMA 完整协议栈实现(工程级可直接编译)-【1】
javascript·stm32·单片机·嵌入式硬件·lora·自组网·smart tdma
竹林81810 小时前
用 wagmi v2 踩坑两天,我终于搞懂了多链钱包切换
前端·javascript
子云zy11 小时前
JS 对象与包装类:new 做了什么?字符串为什么有 length?
前端·javascript
茶底世界之下12 小时前
你的 Mac 里,藏着一支 AI 开发团队
前端·javascript
小白学大数据12 小时前
Playwright 爬虫:Python 爬取 JS 渲染的 JSP 网站
开发语言·javascript·爬虫·python·数据分析