real-vue3-easy-form
v1.0.4
Published
基于 Vue 3 + Element Plus 的动态表单组件库,支持配置化生成表单
Maintainers
Readme
Real Vue3 Easy Form 使用手册
基于 Vue 3 + Element Plus 的动态表单组件库,支持配置化生成表单。
目录
安装
环境要求
- Vue 3.2.0+
- Element Plus 2.2.0+
安装命令
# 使用 npm
npm install real-vue3-easy-form
# 使用 yarn
yarn add real-vue3-easy-form
# 使用 pnpm
pnpm add real-vue3-easy-form完整引入
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import EasyForm from 'real-vue3-easy-form'
import 'real-vue3-easy-form/dist/style.css'
const app = createApp(App)
app.use(ElementPlus)
app.use(EasyForm)
app.mount('#app')快速开始
基本用法
<template>
<DynamicForm
:fields="formFields"
:model-value="formData"
@update:model-value="handleUpdate"
@submit="handleSubmit"
/>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
import { DynamicForm } from 'real-vue3-easy-form'
import type { FieldConfig } from 'real-vue3-easy-form'
const formFields: FieldConfig[] = [
{
type: 'text',
label: '用户名',
prop: 'username',
placeholder: '请输入用户名',
required: true,
},
{
type: 'password',
label: '密码',
prop: 'password',
placeholder: '请输入密码',
required: true,
},
]
const formData = reactive({
username: '',
password: '',
})
const handleUpdate = (val: Record<string, any>) => {
Object.assign(formData, val)
}
const handleSubmit = (values: Record<string, any>) => {
console.log('表单数据:', values)
}
</script>基础配置
字段通用属性
| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| type | 字段类型(必填) | string | - |
| label | 字段标签 | string | - |
| prop | 字段属性名(必填) | string | - |
| placeholder | 占位文本 | string | - |
| disabled | 是否禁用 | boolean | false |
| readonly | 是否只读 | boolean | false |
| required | 是否必填 | boolean | false |
| clearable | 是否可清空 | boolean | false |
| col | 栅格列宽(1-24) | number | 24 |
| offset | 栅格偏移 | number | 0 |
| className | 自定义类名 | string | - |
| show | 是否显示 | boolean | true |
| rules | 验证规则 | array | - |
| defaultValue | 默认值 | any | - |
字段类型详解
输入类
1. 文本输入 (text)
{
type: 'text',
label: '文本输入',
prop: 'text',
placeholder: '请输入文本',
required: true,
clearable: true,
col: 12,
}2. 文本域 (textarea)
{
type: 'textarea',
label: '文本域',
prop: 'textarea',
placeholder: '请输入多行文本',
clearable: true,
col: 12,
}3. 数字输入 (number)
{
type: 'number',
label: '数字输入',
prop: 'number',
placeholder: '请输入数字',
min: 0, // 最小值
max: 100, // 最大值
precision: 2, // 小数位数
step: 0.1, // 步长
col: 12,
}4. 密码输入 (password)
{
type: 'password',
label: '密码输入',
prop: 'password',
placeholder: '请输入密码',
clearable: true,
col: 12,
}选择类
1. 下拉选择 (select)
{
type: 'select',
label: '下拉选择',
prop: 'select',
placeholder: '请选择',
options: [
{ label: '选项一', value: 1 },
{ label: '选项二', value: 2 },
{ label: '选项三', value: 3 },
],
clearable: true,
col: 12,
}2. 单选按钮 (radio)
{
type: 'radio',
label: '单选按钮',
prop: 'radio',
options: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 },
],
col: 12,
}3. 复选框组 (checkbox)
{
type: 'checkbox',
label: '复选框',
prop: 'checkbox',
options: [
{ label: '阅读', value: 'reading' },
{ label: '运动', value: 'sports' },
{ label: '音乐', value: 'music' },
{ label: '旅行', value: 'travel' },
],
col: 24,
}4. 开关 (switch)
{
type: 'switch',
label: '开关',
prop: 'switch',
activeText: '开', // 开启状态文本
inactiveText: '关', // 关闭状态文本
activeColor: '#67C23A', // 开启状态颜色
inactiveColor: '#909399', // 关闭状态颜色
col: 12,
}5. 滑块 (slider)
// 普通滑块
{
type: 'slider',
label: '滑块',
prop: 'slider',
min: 0,
max: 100,
step: 5,
col: 12,
}
// 范围滑块
{
type: 'slider',
label: '范围滑块',
prop: 'sliderRange',
min: 0,
max: 100,
step: 1,
range: true, // 开启范围选择
marks: { 0: '0%', 50: '50%', 100: '100%' }, // 刻度标记
col: 24,
}日期时间类
1. 日期选择 (date)
{
type: 'date',
label: '日期选择',
prop: 'date',
placeholder: '请选择日期',
format: 'YYYY-MM-DD', // 显示格式
valueFormat: 'YYYY-MM-DD', // 值格式
clearable: true,
col: 8,
}2. 时间选择 (time)
{
type: 'time',
label: '时间选择',
prop: 'time',
placeholder: '请选择时间',
format: 'HH:mm:ss',
valueFormat: 'HH:mm:ss',
clearable: true,
col: 8,
}3. 日期时间选择 (datetime)
{
type: 'datetime',
label: '日期时间',
prop: 'datetime',
placeholder: '请选择日期时间',
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
clearable: true,
col: 8,
}树形选择
1. 普通树形选择 (tree_select)
{
type: 'tree_select',
label: '树形选择',
prop: 'treeSelect',
placeholder: '请选择',
clearable: true,
filterable: true, // 支持搜索
defaultExpandAll: true, // 默认展开全部
nodeKey: 'id', // 节点唯一标识字段
treeData: [
{
id: 1,
label: '技术部',
children: [
{ id: 11, label: '前端组', children: [{ id: 111, label: 'Vue小组' }, { id: 112, label: 'React小组' }] },
{ id: 12, label: '后端组', children: [{ id: 121, label: 'Java小组' }, { id: 122, label: 'Python小组' }] },
{ id: 13, label: '移动端组' },
]
},
{
id: 2,
label: '运营部',
children: [{ id: 21, label: '市场组' }, { id: 22, label: '策划组' }]
},
{ id: 3, label: '人事部' },
{ id: 4, label: '财务部' },
],
col: 12,
}2. 多选树形选择 (tree_select)
{
type: 'tree_select',
label: '多选树形',
prop: 'treeSelectMultiple',
placeholder: '请选择',
clearable: true,
filterable: true,
checkStrictly: true, // 是否严格的遵守父子不互相关联
showCheckbox: true, // 显示复选框
defaultExpandAll: true,
nodeKey: 'id',
treeMultiple: true, // 开启多选
treeData: [
{ id: 1, label: '技术部', children: [{ id: 11, label: '前端' }, { id: 12, label: '后端' }] },
{ id: 2, label: '运营部' },
{ id: 3, label: '人事部' },
],
col: 12,
}高级组件
1. 评分 (rate)
{
type: 'rate',
label: '评分',
prop: 'rate',
max: 5, // 最大分值
allowHalf: false, // 是否允许半选
showText: true, // 显示辅助文字
texts: ['极差', '失望', '一般', '满意', '惊喜'],
col: 12,
}2. 颜色选择器 (color_picker)
{
type: 'color_picker',
label: '颜色选择',
prop: 'colorPicker',
showAlpha: false, // 是否支持透明度选择
colorFormat: 'hex', // 颜色的格式 (hex/rgb/hsl)
col: 12,
}3. 图标选择器 (icon_select)
{
type: 'icon_select',
label: '图标选择',
prop: 'iconSelect',
placeholder: '请选择图标',
iconSearchable: true, // 图标可搜索
iconShowTabs: true, // 显示分类标签
showInputIcon: true, // 在输入框中显示图标
col: 24,
}4. 富文本编辑器 (editor)
{
type: 'editor',
label: '富文本编辑器',
prop: 'editor',
placeholder: '请输入内容...',
height: 300, // 编辑器高度
toolbarConfig: {
excludeKeys: ['group-video'] // 排除的工具栏功能
},
col: 24,
}上传类
1. 图片上传 (image)
{
type: 'image',
label: '图片上传',
prop: 'image',
accept: 'image/*', // 接受的文件类型
maxCount: 3, // 最大上传数量
action: '/api/upload', // 上传地址
multiple: true, // 是否多选
autoUpload: false, // 是否自动上传
col: 12,
}2. 文件上传 (file)
{
type: 'file',
label: '文件上传',
prop: 'file',
accept: '.pdf,.doc,.docx,.xls,.xlsx', // 接受的文件类型
maxSize: 10, // 单个文件大小限制(MB)
maxCount: 5, // 最大上传数量
action: '/api/upload',
multiple: true,
autoUpload: false,
col: 12,
}字段列表
字段列表是一种特殊类型,可以动态添加/删除多个子项,适合需要输入多条记录的场景。
1. 二维模式 - 成员列表 (fieldlist)
{
type: 'fieldlist',
label: '成员列表',
prop: 'members',
listAddText: '添加成员', // 添加按钮文本
listDeleteText: '删除', // 删除按钮文本
listMaxCount: 10, // 最大条数
listSortable: true, // 是否可拖拽排序
listColumns: [ // 子项的列配置
{
type: 'text',
prop: 'name',
label: '姓名',
placeholder: '请输入姓名'
},
{
type: 'select',
prop: 'role',
label: '角色',
options: [
{ label: '管理员', value: 'admin' },
{ label: '成员', value: 'member' }
]
},
{
type: 'text',
prop: 'email',
label: '邮箱',
placeholder: '请输入邮箱'
},
],
col: 24,
}初始化数据格式:
members: [
{ name: '张三', role: 'admin', email: '[email protected]' },
{ name: '李四', role: 'member', email: '[email protected]' }
]2. 一维模式 - 商品清单 (fieldlist)
{
type: 'fieldlist',
label: '商品清单',
prop: 'products',
listMode: '1d', // 使用一维模式
listItemLabel: 'name', // 显示字段名
listAddText: '添加商品',
listMaxCount: 10,
col: 24,
}初始化数据格式:
products: ['商品A', '商品B']组件属性
DynamicForm 属性
| 属性 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| fields | 字段配置数组(必填) | FieldConfig[] | - |
| modelValue | 表单数据对象(必填) | Record<string, any> | {} |
| rules | 表单验证规则 | Record<string, any[]> | {} |
| labelWidth | 标签宽度 | string \| number | '120px' |
| labelPosition | 标签位置 | 'left' \| 'right' \| 'top' | 'right' |
| size | 表单尺寸 | 'large' \| 'default' \| 'small' | 'default' |
| inline | 是否行内表单 | boolean | false |
| disabled | 是否禁用整个表单 | boolean | false |
| gutter | 栅格间距 | number | 16 |
| showActions | 是否显示操作按钮 | boolean | true |
| submitText | 提交按钮文本 | string | '提交' |
| submitLoading | 提交按钮加载状态 | boolean | false |
| enableDraft | 启用草稿功能 | boolean | false |
| draftKey | 草稿存储键名 | string | 'form_draft' |
| draftTTL | 草稿有效期(毫秒) | number | 7 * 24 * 60 * 60 * 1000 |
| showDraftTip | 显示草稿提示 | boolean | true |
组件事件
DynamicForm 事件
| 事件名 | 说明 | 参数 |
|--------|------|------|
| update:modelValue | 表单数据变化时触发 | (value: Record<string, any>) |
| submit | 提交表单时触发 | (value: Record<string, any>) |
| reset | 重置表单时触发 | () |
| change | 字段值变化时触发 | (field: FieldConfig, value: any) |
| input | 字段输入时触发 | (field: FieldConfig, value: any) |
| validate | 表单验证结果 | (valid: boolean) |
高级功能
1. 草稿保存
开启草稿功能后,表单数据会自动保存到 localStorage,防止意外丢失。
<DynamicForm
:fields="formFields"
:model-value="formData"
:enable-draft="true"
:draft-key="'my-form-draft'"
:draft-ttl="7 * 24 * 60 * 60 * 1000"
:show-draft-tip="true"
@update:model-value="handleUpdate"
@submit="handleSubmit"
/>2. 自定义操作按钮
<template>
<DynamicForm
:fields="formFields"
v-model="formData"
@submit="handleSubmit"
>
<template #actions>
<el-button type="primary" @click="customSubmit">保存</el-button>
<el-button type="success" @click="customSaveDraft">保存草稿</el-button>
<el-button @click="customReset">重置</el-button>
</template>
</DynamicForm>
</template>3. 获取表单实例方法
通过 ref 获取表单实例,可以调用验证、重置等方法。
<template>
<DynamicForm
ref="formRef"
:fields="formFields"
v-model="formData"
/>
<el-button @click="validateForm">验证表单</el-button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { FormInstance } from 'element-plus'
const formRef = ref()
const validateForm = async () => {
const valid = await formRef.value?.validate()
if (valid) {
console.log('表单验证通过')
}
}
// 暴露的方法
// formRef.value?.validate() - 验证表单
// formRef.value?.reset() - 重置表单
// formRef.value?.clearValidate() - 清除验证
// formRef.value?.getData() - 获取表单数据
// formRef.value?.setData(data) - 设置表单数据
</script>4. 动态显示字段 (favisible)
根据其他字段的值动态显示或隐藏字段。
{
type: 'text',
label: '姓名',
prop: 'name',
},
{
type: 'text',
label: '详细地址',
prop: 'address',
favisible: 'name=张三', // 当 name 等于"张三"时显示
}示例代码
完整示例 - 用户信息表单
<template>
<div class="form-demo">
<h1>用户信息表单</h1>
<DynamicForm
ref="formRef"
:fields="formFields"
:model-value="formData"
@update:model-value="(val) => Object.assign(formData, val)"
@submit="handleSubmit"
@reset="handleReset"
/>
<div class="debug-info">
<h3>表单数据预览:</h3>
<pre>{{ JSON.stringify(formData, null, 2) }}</pre>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { DynamicForm } from 'real-vue3-easy-form'
import type { FieldConfig } from 'real-vue3-easy-form'
import { ElMessage } from 'element-plus'
const formFields: FieldConfig[] = [
{
type: 'text',
label: '姓名',
prop: 'name',
placeholder: '请输入姓名',
required: true,
col: 12,
},
{
type: 'select',
label: '性别',
prop: 'gender',
options: [
{ label: '男', value: 'male' },
{ label: '女', value: 'female' },
],
col: 12,
},
{
type: 'number',
label: '年龄',
prop: 'age',
min: 1,
max: 150,
col: 12,
},
{
type: 'date',
label: '出生日期',
prop: 'birthday',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
col: 12,
},
{
type: 'text',
label: '手机号',
prop: 'phone',
placeholder: '请输入手机号',
required: true,
col: 12,
},
{
type: 'text',
label: '邮箱',
prop: 'email',
placeholder: '请输入邮箱',
rules: [
{ type: 'email', message: '请输入正确的邮箱格式' }
],
col: 12,
},
{
type: 'textarea',
label: '个人简介',
prop: 'bio',
placeholder: '请输入个人简介',
col: 24,
},
]
const formData = reactive({
name: '',
gender: '',
age: null,
birthday: '',
phone: '',
email: '',
bio: '',
})
const handleSubmit = (values: Record<string, any>) => {
console.log('提交数据:', values)
ElMessage.success('提交成功!')
}
const handleReset = () => {
ElMessage.info('表单已重置')
}
</script>
<style scoped>
.form-demo {
max-width: 800px;
margin: 40px auto;
padding: 20px;
}
.debug-info {
margin-top: 30px;
padding: 15px;
background: #f5f7fa;
border-radius: 8px;
}
.debug-info pre {
background: #fff;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}
</style>更新日志
v1.0.3 (当前版本)
- 支持多种字段类型(输入、选择、日期、树形、上传等)
- 内置富文本编辑器(wangEditor)
- 支持字段列表(动态添加/删除多条记录)
- 支持草稿自动保存
- 支持动态显示/隐藏字段
常见问题
1. 为什么表单无法输入或选择?
确保使用了正确的绑定方式:
<!-- 正确 -->
<DynamicForm
:model-value="formData"
@update:model-value="(val) => Object.assign(formData, val)"
/>
<!-- 错误 -->
<DynamicForm v-model="formData" />2. 如何自定义验证规则?
{
type: 'text',
label: '邮箱',
prop: 'email',
rules: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
]
}3. 如何获取表单实例的方法?
const formRef = ref()
// 验证表单
const valid = await formRef.value?.validate()
// 获取数据
const data = formRef.value?.getData()
// 设置数据
formRef.value?.setData({ name: '张三' })
// 重置表单
formRef.value?.reset()License
MIT License - 2024
