Skip to content

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 属性

属性名类型默认值说明
dynamicTitleString''动态标题前缀,配合id字段实现"新增/编辑"自动切换
rulesObject{}Element Plus 表单验证规则
titleString-对话框标题(Element Plus Dialog 属性)
widthString-对话框宽度(Element Plus Dialog 属性)
align-centerBooleantrue是否居中对齐
draggableBooleantrue是否可拖拽
close-on-click-modalBooleanfalse是否可通过点击遮罩关闭
destroy-on-closeBooleantrue关闭时销毁内部元素

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')
}

注意事项

  1. 表单验证:使用 rules 属性启用表单验证,验证通过后才会触发 confirm 事件
  2. 数据深拷贝:通过 action 方法传入的数据会被深拷贝,避免引用问题
  3. 加载状态:组件自动管理 loading 状态,无需手动控制
  4. 内存管理:设置 destroy-on-close 为 true,关闭时自动销毁内部元素
  5. 动态标题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)
}