背景
在 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()) {
// 提交数据
}
}
技术方案
核心思路
- 保持接口不变: 保持原有的 Promise 接口,确保调用方无需修改
- 状态管理: 使用组件状态控制弹窗显示和数据
- 自定义渲染: 使用 Vue 模板替代 JSX
- 事件封装: 通过保存 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 模板 |
| 样式控制 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 调试体验 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 代码组织 | 集中在一处 | 分离清晰 |
| 学习曲线 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
最佳实践
- 封装通用组件: 可以将这个模式进一步封装成通用的确认弹窗组件,供整个项目使用
- 保持接口稳定: 始终保持 Promise 接口,避免大面积修改调用方
- 状态清理: 弹窗关闭时一定要清理相关状态,避免内存泄漏
- 样式复用: 将弹窗的通用样式提取到全局样式或组件中
- 类型安全: 如果使用 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> 是一个提升代码可维护性和可定制性的好做法。核心要点是:
- ✅ 使用 Promise 保持接口不变
- ✅ 使用状态管理弹窗显示
- ✅ 使用 Vue 模板替代 JSX
- ✅ 自定义 footer 获得完全控制
- ✅ 及时清理状态避免内存问题
这种模式可以广泛应用于 Vue + Ant Design Vue 的项目中,希望对你有所帮助!