Skip to content

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行内表单booleanfalse
disabled是否禁用booleanfalse
elSize组件尺寸'small' | 'large' | 'default''default'
isFlexible是否可折叠booleanfalse
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是否隐藏booleanfalse
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搜索按钮内置搜索按钮

Released under the MIT License.