将 $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 的项目中,希望对你有所帮助!

相关推荐
费曼学习法1 小时前
Vue 3 编译优化揭秘:静态提升与 PatchFlags 的极致性能
javascript·vue.js
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_27:(深入理解 HTML 属性反射机制)
前端·javascript·ui·html·音视频·媒体
小矮马2 小时前
qiankun 微前端集成子项目
javascript
Hello--_--World2 小时前
React:useRef 超详细教程、forwardRef 详解、useImperativeHandle详解
前端·javascript·react.js
xuankuxiaoyao2 小时前
vue.js 课程自己编写小游戏
前端·javascript·vue.js
天一生水water2 小时前
VUE3入门
javascript
yqcoder2 小时前
JavaScript 浅拷贝:只复制“第一层”的艺术
开发语言·javascript·ecmascript
yqcoder2 小时前
JavaScript 闭包:函数背后的“背包”
开发语言·javascript·ecmascript
threelab3 小时前
挑战AI辅助从零构建3D模型编辑器:01基于Vue3 + Three.js的现代化架构设计
javascript·人工智能·3d·前端框架·着色器