ByForm 表单组件
基于 Element Plus 的表单组件,提供更便捷的表单配置和验证功能。支持多种表单控件类型,内置表单验证,灵活的布局配置。
基础用法
简单表单
::: demo
vue
<template>
<by-form :model="formData" :rules="rules" label-width="120px" @submit="handleSubmit">
<by-form-item label="用户名" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名" />
</by-form-item>
<by-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" />
</by-form-item>
<by-form-item label="年龄" prop="age">
<el-input-number v-model="formData.age" :min="1" :max="120" />
</by-form-item>
<by-form-item>
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button @click="handleReset">重置</el-button>
</by-form-item>
</by-form>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
const formData = reactive({
username: '',
email: '',
age: 18,
})
const rules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' },
],
email: [
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' },
],
age: [
{ required: true, message: '请输入年龄', trigger: 'blur' },
{ type: 'number', min: 1, max: 120, message: '年龄必须在 1 到 120 之间', trigger: 'blur' },
],
}
const handleSubmit = () => {
console.log('表单数据:', formData)
ElMessage.success('提交成功')
}
const handleReset = () => {
Object.assign(formData, {
username: '',
email: '',
age: 18,
})
}
</script>
::: ### 配置化表单 ::: demo ```vue
<template>
<by-form v-model="formData" :form-items="formItems" label-width="120px" @submit="handleSubmit" @reset="handleReset" />
</template>
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
const formData = reactive({
name: '',
email: '',
age: 18,
gender: '',
city: '',
hobbies: [],
description: '',
})
const formItems = ref([
{
field: 'name',
type: 'input',
label: '姓名',
attrs: {
placeholder: '请输入姓名',
clearable: true,
},
rules: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
},
{
field: 'email',
type: 'input',
label: '邮箱',
attrs: {
placeholder: '请输入邮箱',
type: 'email',
},
rules: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' },
],
},
{
field: 'age',
type: 'inputNumber',
label: '年龄',
attrs: {
min: 1,
max: 120,
placeholder: '请输入年龄',
},
rules: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
},
{
field: 'gender',
type: 'radio',
label: '性别',
options: [
{ label: '男', value: 'male' },
{ label: '女', value: 'female' },
],
rules: [{ required: true, message: '请选择性别', trigger: 'change' }],
},
{
field: 'city',
type: 'select',
label: '城市',
attrs: {
placeholder: '请选择城市',
clearable: true,
},
options: [
{ label: '北京', value: 'beijing' },
{ label: '上海', value: 'shanghai' },
{ label: '广州', value: 'guangzhou' },
{ label: '深圳', value: 'shenzhen' },
],
rules: [{ required: true, message: '请选择城市', trigger: 'change' }],
},
{
field: 'hobbies',
type: 'checkbox',
label: '爱好',
multiple: true,
options: [
{ label: '阅读', value: 'reading' },
{ label: '音乐', value: 'music' },
{ label: '运动', value: 'sports' },
{ label: '旅行', value: 'travel' },
],
},
{
field: 'description',
type: 'input',
label: '描述',
attrs: {
type: 'textarea',
rows: 3,
placeholder: '请输入描述',
},
},
{
type: 'formButtons',
otherOptions: {
submitText: '提交',
resetText: '重置',
},
},
])
const handleSubmit = (formData) => {
console.log('表单数据:', formData)
ElMessage.success('提交成功')
}
const handleReset = () => {
console.log('表单重置')
}
</script>
::: ### 搜索表单 ::: demo ```vue
<template>
<by-form
v-model="searchData"
:form-items="searchItems"
label-width="100px"
@submit="handleSearch"
@reset="handleReset"
/>
</template>
<script setup>
import { ref, reactive } from 'vue'
const searchData = reactive({
keyword: '',
status: '',
dateRange: [],
category: '',
})
const searchItems = ref([
{
field: 'keyword',
type: 'input',
label: '关键词',
attrs: {
placeholder: '请输入关键词',
clearable: true,
},
colLayout: {
xs: 24,
sm: 12,
md: 8,
lg: 6,
},
},
{
field: 'status',
type: 'select',
label: '状态',
attrs: {
placeholder: '请选择状态',
clearable: true,
},
options: [
{ label: '启用', value: 'active' },
{ label: '禁用', value: 'inactive' },
],
colLayout: {
xs: 24,
sm: 12,
md: 8,
lg: 6,
},
},
{
field: 'dateRange',
type: 'customDatePicker',
label: '日期范围',
attrs: {
type: 'daterange',
placeholder: '请选择日期范围',
clearable: true,
},
colLayout: {
xs: 24,
sm: 24,
md: 16,
lg: 12,
},
},
{
field: 'category',
type: 'commonSelector',
label: '分类',
attrs: {
placeholder: '请选择分类',
type: 'border',
multiple: true,
},
options: [
{ id: 1, name: '技术', initial: 'J' },
{ id: 2, name: '产品', initial: 'C' },
{ id: 3, name: '设计', initial: 'S' },
{ id: 4, name: '运营', initial: 'Y' },
],
colLayout: {
xs: 24,
sm: 24,
md: 8,
lg: 6,
},
},
{
type: 'formButtons',
otherOptions: {
submitText: '搜索',
resetText: '重置',
},
},
])
const handleSearch = (formData) => {
console.log('搜索条件:', formData)
}
const handleReset = () => {
console.log('重置搜索')
}
</script>
::: ### 可折叠表单 ::: demo ```vue
<template>
<by-form
v-model="formData"
:form-items="formItems"
:is-flexible="true"
:flexible="flexibleConfig"
label-width="120px"
@submit="handleSubmit"
@reset="handleReset"
/>
</template>
<script setup>
import { ref, reactive } from 'vue'
const formData = reactive({
name: '',
email: '',
phone: '',
address: '',
company: '',
position: '',
department: '',
salary: '',
})
const flexibleConfig = reactive({
foldField: ['company', 'position', 'department', 'salary'],
unfold: false,
})
const formItems = ref([
{
field: 'name',
type: 'input',
label: '姓名',
attrs: {
placeholder: '请输入姓名',
},
rules: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
},
{
field: 'email',
type: 'input',
label: '邮箱',
attrs: {
placeholder: '请输入邮箱',
type: 'email',
},
rules: [{ required: true, message: '请输入邮箱', trigger: 'blur' }],
},
{
field: 'phone',
type: 'input',
label: '电话',
attrs: {
placeholder: '请输入电话',
},
},
{
field: 'address',
type: 'input',
label: '地址',
attrs: {
placeholder: '请输入地址',
},
},
{
field: 'company',
type: 'input',
label: '公司',
attrs: {
placeholder: '请输入公司名称',
},
},
{
field: 'position',
type: 'input',
label: '职位',
attrs: {
placeholder: '请输入职位',
},
},
{
field: 'department',
type: 'select',
label: '部门',
attrs: {
placeholder: '请选择部门',
},
options: [
{ label: '技术部', value: 'tech' },
{ label: '产品部', value: 'product' },
{ label: '设计部', value: 'design' },
{ label: '运营部', value: 'operation' },
],
},
{
field: 'salary',
type: 'inputNumber',
label: '薪资',
attrs: {
placeholder: '请输入薪资',
min: 0,
},
},
{
type: 'formButtons',
otherOptions: {
submitText: '提交',
resetText: '重置',
},
},
])
const handleSubmit = (formData) => {
console.log('表单数据:', formData)
}
const handleReset = () => {
console.log('表单重置')
}
</script>::: ## API
Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| modelValue | 表单数据对象 | Record<string, any> | {} |
| formItems | 表单项配置数组 | IFormItems[] | [] |
| labelWidth | 标签宽度 | string | '80px' |
| labelPosition | 标签位置 | 'left' | 'right' | 'top' | 'right' |
| inline | 行内表单 | boolean | false |
| disabled | 是否禁用 | boolean | false |
| elSize | 组件尺寸 | 'small' | 'large' | 'default' | 'default' |
| isFlexible | 是否可折叠 | boolean | false |
| flexible | 折叠配置 | object | { foldField: 'none', unfold: false } |
| colLayout | 栅格布局 | object | { xs: 12, sm: 8, md: 6, lg: 6, xl: 4 } |
| otherOptions | 其他选项 | object | { submit: true, reset: true, submitText: '搜索', resetText: '重置', showSubmitIcon: true } |
Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:modelValue | 表单数据变化时触发 | (values: Record<string, any>) |
| change | 表单项值变化时触发 | (values: Record<string, any>) |
| submit | 表单提交时触发 | (formData: Record<string, any>) |
| reset | 表单重置时触发 | () |
| queryBtnClick | 搜索按钮点击时触发 | () |
| resetBtnClick | 重置按钮点击时触发 | (cloneModelValue: Record<string, any>, cloneFormItems: IFormItems[]) |
Methods
| 方法名 | 说明 | 参数 |
|---|---|---|
| submit | 提交表单 | () |
| reset | 重置表单 | () |
IFormItems 数据结构
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| field | 字段名 | string | - |
| type | 控件类型 | string | - |
| label | 标签文本 | string | - |
| attrs | 控件属性 | object | {} |
| options | 选项数据 | array | [] |
| rules | 验证规则 | array | [] |
| colLayout | 栅格布局 | object | - |
| labelWidth | 标签宽度 | string | - |
| hidden | 是否隐藏 | boolean | false |
| itemStyle | 表单项样式 | object | - |
| props | 组件属性配置 | object | - |
| slotsName | 插槽名称 | object | - |
| otherOptions | 其他选项 | object | - |
| suffixInputField | 后缀输入字段 | string | - |
| startTimeField | 开始时间字段 | string | - |
| endTimeField | 结束时间字段 | string | - |
支持的控件类型
| 类型 | 说明 | 对应组件 |
|---|---|---|
| input | 输入框 | el-input |
| inputNumber | 数字输入框 | el-input-number |
| select | 选择器 | el-select |
| radio | 单选框 | el-radio-group |
| checkbox | 复选框 | el-checkbox-group |
| datepicker | 日期选择器 | el-date-picker |
| customDatePicker | 自定义日期选择器 | CustomDatePicker |
| treeSelect | 树形选择器 | el-tree-select |
| cascader | 级联选择器 | el-cascader |
| switch | 开关 | el-switch |
| commonSelector | 通用选择器 | ByCommonSelector |
| custom | 自定义组件 | 插槽 |
| formButtons | 表单按钮 | 内置按钮组 |
| search | 搜索按钮 | 内置搜索按钮 |
