vue-dc-form
v1.0.6
Published
XForm 是一个基于 Vue 3 的表单组件库,提供了表单的封装和动态组件渲染功能。
Readme
本demo插件的说明
XForm 表单组件
XForm 是一个基于 Vue 3 的表单组件库,提供了表单的封装和动态组件渲染功能。
特性
- 支持 Element Plus 大部分表单组件
- 基于配置驱动,简化表单开发
- 内置表单验证功能
- 支持自定义插槽
- 提供表单 API 控制方法
目录结构
src/
├─ components/
│ └─ DcForm/ # 表单封装核心目录
│ ├── index.ts # 导出文件
│ └── src/ # 源代码目录
│ ├── FormWrapper.vue # 表单容器(处理校验/数据绑定)
│ ├── UploadWrapper.vue # 上传组件包装器
│ ├── hooks.ts # 钩子函数(如useXFormApi)
│ ├── types/ # 类型声明文件夹
│ │ └── types.ts # 类型声明
│ └── tools/ # 工具函数
│ ├── componentRegistry.ts # 组件注册表
│ ├── registerElementComponents.ts # 注册Element组件
│ ├── elItem.ts # Element表单项目处理
│ └── rule.ts # 表单验证规则
组件参数
组件参数
config数组配置项-必传-具体对象配置见 src-types-types.ts- FormItemConfig-可参考最后配置示例
initialValues表单数据对象-必传
footerShow 是否显示 提交 重置 按钮 -可选(默认不显示)
……其他原el的Form API - 可选-比如表单尺寸……
// FormItemConfig参数说明
/** 基础配置 */
interface BaseFormItemConfig {
/** 组件绑定的属性名 */
prop: string
/** 组件的label */
label?: string
value?: any
/** 占位符(eg:请输入 ) */
placeholder?: string
/** 组件的参数配置 */
componentProps?: Record<string, any>
// 校验规则集成 -el 是基于( async-validator ) 封装的校验规则
rules?: Array<RuleItem>
// 自定义插槽支持
slotName?: string
/** 自定义或者原el组件中的事件 */
events?: Record<string, (...args: any[]) => void>
}
/** 表单项基础配置 */
export interface FormItemConfig extends BaseFormItemConfig {
/** 为哪种类型(组件) */
type: ComponentType
/** 组件的子组件(用于扩展) 如:单选是el-radio-group和el-radio组合的 */
children?: childrenConfig
/** item的label宽度 */
labelWidth?: string | number
/** 是否在行内显示校验信息 */
inlineMessage?: string | boolean
/** 表单item的尺寸 */
size?: '' | 'large' | 'default' | 'small'
/** item的宽度 */
width?: string | number
}
/** 子组件基础配置 */
export interface childrenConfig extends BaseFormItemConfig {
/** 子组件类型 */
type: childrenType
/** 用于不用label展示的项 */
htmlText?: string
prop?: string
data: childrenConfig[]
}使用示例
<template>
<XForm :config="formConfig" :initialValues="formData" @register="useFormApi.register" />
</template>
<script setup>
import { XForm, type FormItemConfig, useXFormApi } from 'vue-dc-form'
// 组件里面的方法useFormApi是ref对象
const useFormApi = useXFormApi();
const formConfig = ref<FormItemConfig[]>([
{
type: 'el-input',
label: '用户名',
prop: 'username',
placeholder: '请输入用户名',
rules: [{ required: true, message: '用户名不能为空' }]
},
{
type: 'el-input',
label: '密码',
prop: 'password',
componentProps: {
type: 'password'
},
rules: [{ required: true, message: '密码不能为空' }]
}
])
const formData = ref({
username: '',
password: ''
})
</script>表单方法
// 提交表单
useFormApi.value
.submit()
.then((data) => {
console.log('表单数据:', data)
})
.catch((err) => {
console.error('表单验证失败:', err)
})
// 重置表单
useFormApi.value.resetFields()
// 手动验证表单
useFormApi.value.validate()支持的表单组件
XForm 支持以下 Element Plus 表单组件:
- 输入框 (el-input)
- 数字输入框 (el-input-number)
- 选择器 (el-select)
- 日期选择器 (el-date-picker)
- 时间选择器 (el-time-picker)
- 单选框 (el-radio-group)
- 多选框 (el-checkbox-group)
- 开关 (el-switch)
- 滑块 (el-slider)
- 评分 (el-rate)
- 文件上传 (el-upload)
- 穿梭框 (el-transfer)
- 级联选择器 (el-cascader)
- 颜色选择器 (el-color-picker)
自定义插槽
XForm 支持通过插槽自定义表单内容:
<XForm :config="formConfig">
<template #test_slot="{ formData }">
<el-button @click="handleCustomAction">自定义操作</el-button>
</template>
</XForm>维护
增加自定义事件
// 1.src/types/types.ts文件中
export interface XFormApiEvents {
// ……………………
// 在这先注册
}
// 2.src/FormWrapper.vue
const api: XFormApi = {
// ………………
// 添加自定义事件
}配置示例
const formConfig = ref<FormItemConfig[]>([
{ type: 'slot', slotName: 'test_slot', prop: 'test_slot', label: '测试' },
{
type: 'el-input',
label: '姓名',
prop: 'name',
placeholder: '请输入姓名',
width: 12,
},
{
type: 'el-input',
label: '密码',
prop: 'password',
width: 12,
componentProps: { type: 'password' },
placeholder: '请输入姓名',
},
{
type: 'el-radio-group', // 单选框组
label: '性别',
prop: 'gender',
width: 24,
componentProps: { 'text-color': '#af1967' },
children: {
type: 'el-radio',
data: [
{ htmlText: '男', value: 'man', prop: 'male' },
{ htmlText: '女', value: 'girl', prop: 'male' },
],
},
},
{
label: '日期',
prop: 'date',
type: 'el-date-picker',
width: 24,
componentProps: {
type: 'date',
placeholder: '选择日期',
valueFormat: 'YYYY-MM-DD',
},
rules: [{ required: true, message: '请选择日期', trigger: 'change' }],
},
{
type: 'el-checkbox-group',
label: '爱好',
prop: 'hobby',
width: 24,
children: {
type: 'el-checkbox',
data: [
{ htmlText: '吃饭', value: 'eat', prop: 'eat' },
{ htmlText: '睡觉', value: 'sleep', prop: 'sleep' },
{ htmlText: '打豆豆', value: 'do', prop: 'do' },
],
},
events: {
change: (val: any) => {
console.log(val, '----val----')
},
},
},
{
type: 'el-select',
label: '选择角色:',
prop: 'Roles',
placeholder: '请选择角色',
children: {
type: 'el-option',
data: [
{ label: '超级管理员', value: 'admin' },
{ label: '普通用户', value: 'user' },
{ label: '游客', value: 'visitor' },
],
},
componentProps: { multiple: true, collapseTags: true },
events: {
change: (val: any) => {
formData.value.Roles = val
},
},
},
{
type: 'el-cascader',
label: '地址',
prop: 'address',
width: 24,
placeholder: '请选择地址',
events: {
change: (val: any) => {
console.log(val, '------****** val ******------')
},
},
componentProps: {
'popper-append-to-body': false,
size: 'default',
options: [
{
value: 'sc',
label: '四川',
children: [
{
value: 'cd',
label: '成都',
children: [
{ value: 'cdx', label: '成都高新区' },
{ value: 'cdy', label: '成都高新区' },
],
},
],
},
{
value: 'cq',
label: '重庆',
children: [
{ value: 'cqx', label: '渝北区' },
{ value: 'jb', label: '江北区' },
],
},
],
clearable: true, // 可清空
props: {
value: 'value', // 节点值的属性名
label: 'label', // 节点标签的属性名
children: 'children', // 子节点的属性名
},
},
},
{ type: 'el-color-picker', label: '喜欢什么颜色?', prop: 'color', width: 24 },
{
type: 'el-date-picker',
label: '年月日',
prop: 'csnyr',
width: 24,
componentProps: {
type: 'datetime',
placeholder: '选择日期时间',
valueFormat: 'YYYY-MM-DD',
},
},
{
type: 'el-input-number',
label: '年龄',
prop: 'age',
width: 24,
componentProps: {
valueOnClear: 0, // 清空时的值
},
},
{ type: 'el-rate', label: '评分', prop: 'rate', width: 24 },
{ type: 'el-slider', label: '人身进度', prop: 'slider' },
{
type: 'el-switch',
label: '开关',
prop: 'switch',
width: 24,
componentProps: { activeText: '开', inactiveText: '关' },
},
{
type: 'el-time-picker',
label: '时间',
prop: 'time',
width: 24,
componentProps: {
valueFormat: 'HH:mm:ss', // 设置时间格式为 HH:mm:ss
},
},
{ type: 'el-time-select', label: '固定时间', prop: 'gdsj' },
{
type: 'el-upload',
label: '上传图片',
prop: 'file',
componentProps: {
limit: 2,
'auto-upload': false,
'list-type': 'picture-card',
},
events: {
onExceed: (files: any) => {
console.log(files, '------****** files ******------')
},
},
},
])