BaDialog 组件使用文档
组件概述
BaDialog 是一个基于 Element Plus Dialog 封装的高级对话框组件,专为表单场景设计。它集成了表单验证、数据管理、加载状态控制等功能,大大简化了对话框表单的开发流程。
核心特性
- 🎯 智能表单验证:内置 Element Plus 表单验证机制
- ⚡ 数据状态管理:自动管理表单数据和加载状态
- 🔧 灵活的扩展性:支持自定义插槽和事件处理
- 🎨 现代化UI:继承 Element Plus 的设计风格
- 📱 响应式设计:适配不同屏幕尺寸
基础使用
1. 简单表单对话框
vue
<template>
<div>
<el-button @click="openDialog">打开对话框</el-button>
<BaDialog
ref="dialogRef"
title="基本信息"
width="500px"
@confirm="handleSubmit"
>
<template #form="{ form }">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
</template>
</BaDialog>
</div>
</template>
<script setup>
import { ref } from 'vue'
const dialogRef = ref()
const openDialog = () => {
dialogRef.value.action({
name: '',
email: ''
})
}
const handleSubmit = ({ form, visible, loading }) => {
console.log('提交数据:', form.value)
// 模拟异步提交
setTimeout(() => {
$sdk.msgSuccess('提交成功')
visible.value = false
loading.value = false
}, 1000)
}
</script>2. 带验证的复杂表单
vue
<template>
<BaDialog
ref="formDialogRef"
title="用户管理"
:rules="formRules"
width="600px"
@confirm="handleFormSubmit"
>
<template #form="{ form }">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="用户名" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
:disabled="!!form.id"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="真实姓名" prop="realName">
<el-input v-model="form.realName" placeholder="请输入真实姓名" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="手机号" prop="phone">
<el-input v-model="form.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="角色" prop="roleId">
<el-select v-model="form.roleId" placeholder="请选择角色">
<el-option label="管理员" value="admin" />
<el-option label="普通用户" value="user" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
</template>
</BaDialog>
</template>
<script setup>
import { ref } from 'vue'
const formDialogRef = ref()
const formRules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 20, message: '用户名长度3-20位', trigger: 'blur' }
],
realName: [
{ required: true, message: '请输入真实姓名', trigger: 'blur' }
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
],
roleId: [
{ required: true, message: '请选择角色', trigger: 'change' }
]
}
const handleFormSubmit = ({ form, visible, loading }) => {
console.log('验证通过,提交数据:', form.value)
// 提交逻辑...
visible.value = false
}
</script>API 参考
Props 属性
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| dynamicTitle | String | '' | 动态标题前缀,配合id字段实现"新增/编辑"自动切换 |
| rules | Object | {} | Element Plus 表单验证规则 |
| title | String | - | 对话框标题(Element Plus Dialog 属性) |
| width | String | - | 对话框宽度(Element Plus Dialog 属性) |
| align-center | Boolean | true | 是否居中对齐 |
| draggable | Boolean | true | 是否可拖拽 |
| close-on-click-modal | Boolean | false | 是否可通过点击遮罩关闭 |
| destroy-on-close | Boolean | true | 关闭时销毁内部元素 |
Events 事件
| 事件名 | 参数 | 说明 |
|---|---|---|
| confirm | ({ form, visible, loading }) | 确认按钮点击事件,表单验证通过后触发 |
| cancel | - | 取消按钮点击事件 |
Slots 插槽
| 插槽名 | 作用域参数 | 说明 |
|---|---|---|
| default | - | 对话框主体内容 |
| form | 表单内容区域,form为响应式表单数据对象 | |
| footer | - | 底部按钮区域 |
Methods 方法
通过 ref 可以调用组件的以下方法:
action(data, callback)
打开对话框并初始化数据
javascript
// 参数说明:
// data: Object - 初始化的表单数据
// callback: Function - 对话框打开后的回调函数
// 使用示例:
dialogRef.value.action({ name: '张三' }, () => {
console.log('对话框已打开')
})confirm(addFn, successCallback, updateFn, idKey)
简化版的 CRUD 操作方法
javascript
// 参数说明:
// addFn: Function - 新增操作函数
// successCallback: Function - 操作成功后的回调
// updateFn: Function - 更新操作函数(可选)
// idKey: String - ID 字段名,默认为 'id'
// 使用示例:
// 新增模式
dialogRef.value.confirm(
addUserApi,
() => { refreshList() }
)
// 编辑模式(根据 idKey 判断)
dialogRef.value.confirm(
addUserApi,
() => { refreshList() },
updateUserApi,
'userId'
)完整业务示例
用户管理系统
vue
<template>
<div class="user-management">
<!-- 操作按钮 -->
<div class="toolbar">
<el-button type="primary" @click="handleAdd">新增用户</el-button>
<el-button @click="handleEdit(selectedUser)" :disabled="!selectedUser">编辑用户</el-button>
<el-button type="danger" @click="handleDelete" :disabled="!selectedUser">删除用户</el-button>
</div>
<!-- 用户列表 -->
<el-table
:data="userList"
@current-change="handleCurrentChange"
highlight-current-row
>
<el-table-column prop="username" label="用户名" />
<el-table-column prop="realName" label="真实姓名" />
<el-table-column prop="phone" label="手机号" />
<el-table-column prop="email" label="邮箱" />
<el-table-column prop="roleName" label="角色" />
<el-table-column prop="status" label="状态">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
</el-table>
<!-- 用户管理对话框 -->
<BaDialog
ref="userDialogRef"
:dynamic-title="'用户'"
:rules="userRules"
width="600px"
@confirm="handleUserSubmit"
@cancel="handleCancel"
>
<template #form="{ form }">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="用户名" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
:disabled="!!form.id"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="真实姓名" prop="realName">
<el-input v-model="form.realName" placeholder="请输入真实姓名" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="手机号" prop="phone">
<el-input v-model="form.phone" placeholder="请输入手机号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="角色" prop="roleId">
<el-select v-model="form.roleId" placeholder="请选择角色" style="width: 100%">
<el-option
v-for="role in roleOptions"
:key="role.id"
:label="role.name"
:value="role.id"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
</template>
</BaDialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { userService, roleService } from '@/api'
const userDialogRef = ref()
const userList = ref([])
const selectedUser = ref(null)
const roleOptions = ref([])
// 表单验证规则
const userRules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 20, message: '用户名长度3-20位', trigger: 'blur' }
],
realName: [
{ required: true, message: '请输入真实姓名', trigger: 'blur' }
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
],
roleId: [
{ required: true, message: '请选择角色', trigger: 'change' }
]
}
// 操作方法
const handleAdd = () => {
userDialogRef.value.action({
status: 1 // 默认启用
})
}
const handleEdit = (user) => {
if (!user) {
$sdk.msgWarning('请先选择用户')
return
}
userDialogRef.value.action(user)
}
const handleDelete = async () => {
if (!selectedUser.value) {
$sdk.msgWarning('请先选择用户')
return
}
try {
await $sdk.confirm('确定要删除该用户吗?')
await userService.delete(selectedUser.value.id)
$sdk.msgSuccess('删除成功')
refreshList()
} catch (error) {
console.error('删除失败:', error)
}
}
const handleUserSubmit = async ({ form, visible, loading }) => {
try {
if (form.value.id) {
// 编辑模式
await userService.update(form.value)
$sdk.msgSuccess('编辑成功')
} else {
// 新增模式
await userService.add(form.value)
$sdk.msgSuccess('新增成功')
}
visible.value = false
refreshList()
} catch (error) {
console.error('提交失败:', error)
} finally {
loading.value = false
}
}
const handleCancel = () => {
console.log('取消操作')
}
const handleCurrentChange = (currentRow) => {
selectedUser.value = currentRow
}
// 数据获取
const refreshList = async () => {
try {
const res = await userService.getList()
userList.value = res.data
} catch (error) {
console.error('获取用户列表失败:', error)
}
}
const getRoles = async () => {
try {
const res = await roleService.getList()
roleOptions.value = res.data
} catch (error) {
console.error('获取角色列表失败:', error)
}
}
onMounted(() => {
refreshList()
getRoles()
})
</script>
<style scoped>
.user-management {
padding: 20px;
}
.toolbar {
margin-bottom: 20px;
}
.toolbar .el-button {
margin-right: 10px;
}
</style>高级用法
1. 动态标题实现
vue
<template>
<BaDialog
ref="dynamicDialogRef"
dynamic-title="商品"
width="500px"
>
<template #form="{ form }">
<!-- 表单内容 -->
</template>
</BaDialog>
</template>
<script setup>
// 当 form 中有 id 时显示:"编辑商品"
// 当 form 中无 id 时显示:"新增商品"
</script>2. 自定义表单验证
vue
<template>
<BaDialog
ref="customValidateRef"
:rules="customRules"
@confirm="handleCustomSubmit"
>
<template #form="{ form }">
<el-form-item label="密码" prop="password">
<el-input
v-model="form.password"
type="password"
show-password
/>
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input
v-model="form.confirmPassword"
type="password"
show-password
/>
</el-form-item>
</template>
</BaDialog>
</template>
<script setup>
const customRules = {
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码至少6位', trigger: 'blur' }
],
confirmPassword: [
{ required: true, message: '请确认密码', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value !== form.value.password) {
callback(new Error('两次输入密码不一致'))
} else {
callback()
}
},
trigger: 'blur'
}
]
}
</script>3. 自定义底部按钮
vue
<template>
<BaDialog ref="customFooterRef" title="自定义底部">
<template #footer>
<el-button @click="handlePreview">预览</el-button>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
<el-button type="success" @click="handleSaveAndClose">保存并关闭</el-button>
</template>
</BaDialog>
</template>最佳实践
1. 表单数据管理
javascript
// 始终在打开对话框时初始化数据
const openDialog = () => {
dialogRef.value.action({
name: '',
email: '',
// 其他字段...
})
}2. 错误处理
javascript
const handleSubmit = async ({ form, visible, loading }) => {
try {
// 表单验证已在组件内部处理
await submitApi(form.value)
$sdk.msgSuccess('操作成功')
visible.value = false
} catch (error) {
$sdk.msgError(error.message || '操作失败')
} finally {
loading.value = false
}
}3. 数据刷新
javascript
const handleSuccess = () => {
// 关闭对话框后刷新数据
refreshList()
// 或者 emit 事件通知父组件
emit('refresh')
}注意事项
- 表单验证:使用
rules属性启用表单验证,验证通过后才会触发confirm事件 - 数据深拷贝:通过
action方法传入的数据会被深拷贝,避免引用问题 - 加载状态:组件自动管理 loading 状态,无需手动控制
- 内存管理:设置
destroy-on-close为 true,关闭时自动销毁内部元素 - 动态标题:
dynamicTitle需要配合表单中的id字段使用
常见问题
Q: 如何在对话框关闭后清空表单?
A: 可以在 cancel 事件中处理:
javascript
const handleCancel = () => {
dialogRef.value.form = {} // 清空表单数据
}Q: 如何实现表单字段联动?
A: 利用 Vue 的响应式特性:
vue
<template #form="{ form }">
<el-form-item label="省份" prop="province">
<el-select v-model="form.province" @change="handleProvinceChange">
<!-- 选项 -->
</el-select>
</el-form-item>
<el-form-item label="城市" prop="city">
<el-select v-model="form.city">
<el-option
v-for="city in cities"
:key="city.id"
:label="city.name"
:value="city.id"
/>
</el-select>
</el-form-item>
</template>Q: 如何自定义提交前的逻辑?
A: 在 confirm 事件中完全控制:
javascript
const handleSubmit = async ({ form, visible, loading }) => {
// 自定义验证
if (!validateForm(form.value)) {
return
}
// 自定义提交逻辑
await customSubmit(form.value)
visible.value = false
}Q: 如何处理异步数据加载?
A: 在打开对话框前预加载数据:
javascript
const openDialog = async () => {
// 预加载所需数据
await loadData()
dialogRef.value.action(initialData)
}