Appearance
DataForm 动态表单
配置驱动的动态表单组件,通过 columns 配置数组自动渲染表单控件。支持动态显示/隐藏、校验、嵌套分组、自定义渲染等。
在线演示
包含 select / radio / checkbox、日期范围、文件上传、可编辑表格、显隐联动:
tsx
import { defineComponent, reactive, h } from 'vue'
import DataForm from '@/components/FormLayout'
import { ElMessage as message } from 'element-plus'
import type { FormProps } from '@/types/DataFormProps'
export default defineComponent({
name: 'DemoDataFormFull',
setup() {
const model = reactive({
name: '',
dept: '',
roles: [],
gender: '',
dateRange: ['', ''],
enable: false,
remark: '',
extra: '',
items: [
{ name: '商品A', qty: 2, price: 99.9 },
],
terms: [
{ title: '付款条款', content: '合同签订后 15 个工作日内支付 30% 预付款' },
],
file: '',
level: '',
})
const columns: FormProps['columns'] = [
// ---- 基础信息 ----
{ label: '姓名', field: 'name', type: 'el-input', span: 12, rules: [{ required: true, message: '请输入姓名' }] },
// ---- data-picker: select ----
{
label: '部门(select)',
field: 'dept',
type: 'data-picker',
span: 12,
props: {
type: 'select',
query: () =>
Promise.resolve([
{ label: '技术部', value: 'tech' },
{ label: '市场部', value: 'mkt' },
{ label: '财务部', value: 'finance' },
]),
},
},
// ---- data-picker: radio ----
{
label: '性别(radio)',
field: 'gender',
type: 'data-picker',
span: 12,
props: {
type: 'radio',
query: () =>
Promise.resolve([
{ label: '男', value: 'male' },
{ label: '女', value: 'female' },
]),
},
},
// ---- data-picker: checkbox ----
{
label: '角色(checkbox)',
field: 'roles',
type: 'data-picker',
span: 12,
props: {
type: 'checkbox',
query: () =>
Promise.resolve([
{ label: '管理员', value: 'admin' },
{ label: '编辑', value: 'editor' },
{ label: '访客', value: 'guest' },
]),
},
},
// ---- date-picker: daterange ----
{
label: '日期范围',
field: 'dateRange',
type: 'date-picker',
span: 24,
props: { type: 'daterange' },
},
// ---- 显隐联动 ----
{
label: '启用扩展字段',
field: 'enable',
type: 'el-switch',
span: 12,
},
{
label: '扩展信息',
field: 'extra',
type: 'el-input',
span: 12,
props: { placeholder: '启用后显示此字段' },
show: (data: any) => !!data.enable,
},
// ---- form-edit-table 数组 ----
{
label: '订单明细(form-edit-table)',
field: 'items',
type: 'form-edit-table',
span: 24,
props: {
editMode: 'table',
height: 160,
min: 1,
columns: [
{ label: '商品名', field: 'name', editType: 'el-input', width: 200 },
{ label: '数量', field: 'qty', editType: 'el-input-number', width: 120, props: { min: 1 } },
{ label: '单价', field: 'price', editType: 'el-input-number', width: 120, props: { min: 0, precision: 2 } },
],
},
},
// ---- form-edit-list ----
{
label: '合同条款(form-edit-list)',
field: 'terms',
type: 'form-edit-list',
span: 24,
props: {
min: 1,
columns: [
{ label: '条款标题', field: 'title', type: 'el-input' },
{ label: '条款内容', field: 'content', type: 'el-input', props: { type: 'textarea' } },
],
},
},
// ---- 日期 + 上传 ----
{ label: '日期', field: 'date', type: 'date-picker', span: 24, props: { type: 'date' } },
{
label: '附件',
field: 'file',
type: 'file-upload',
span: 24,
props: {
type: 'drag',
placeholder: '点击或将文件拖拽到这里上传',
accept: '.jpg,.png,.pdf',
},
},
{ label: '备注', field: 'remark', type: 'el-input', span: 24, props: { type: 'textarea', rows: 3 } },
]
return () => (
<div class="demo-block">
<DataForm
model={model}
columns={columns}
showButton={true}
labelWidth={130}
onConfirm={() => message.success(JSON.stringify(model, null, 2))}
/>
<div style="margin-top:12px;padding:12px;background:#f5f7fa;border-radius:6px;font-size:13px;color:#666;white-space:pre-wrap;font-family:monospace;">
当前数据:{JSON.stringify(model, null, 2)}
</div>
</div>
)
},
})表单配置 (FormProps)
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| model | Object | - | 必填。表单绑定的数据对象 |
| columns | FormColumn[] | - | 必填。字段配置数组 |
| textMode | boolean | false | 文本阅读模式,不显示输入框 |
| labelWidth | string | number | '120px' | 标签宽度 |
| labelPosition | 'left' | 'top' | 'right' | 'right' | 标签对齐位置 |
| inline | boolean | false | 行内表单模式 |
| disabled | boolean | false | 全局禁用 |
| showButton | boolean | false | 是否显示底部提交/重置按钮 |
| buttons | ButtonProps[] | - | 自定义按钮组 |
| onConfirm | Function | - | 确认回调 |
| onCancel | Function | - | 取消回调 |
| onSubmit | Function | - | 提交回调(同 onConfirm) |
字段配置 (FormColumn)
基础属性
| 属性名 | 类型 | 说明 |
|---|---|---|
| field | string | 字段名,对应 model 中的 key。支持路径写法 user.name |
| label | string (动态) | 标签名 |
| type | string | 控件类型。data-picker、el-input、el-select 等 |
| initialValue | any | 默认值,仅在初始化时生效 |
| valueKey | string | 绑定值的属性名,默认为 modelValue |
| span | number (动态) | 栅格占位,24 栅格制,默认 24(占满一行) |
| show | boolean (动态) | 是否显示 |
| destroyOnHide | boolean | 隐藏时是否销毁 DOM 并清空值 |
交互与校验
| 属性名 | 类型 | 说明 |
|---|---|---|
| props | Object (动态) | 透传属性给具体 UI 控件 |
| rules | Rule[] (动态) | 校验规则 |
| required | boolean (动态) | 是否必填 |
| events | Object (动态) | 事件监听,无需 on 前缀 |
| slots | Record<string, ()=>VNode> (动态) | 插槽传递 |
| suffix | VNode (动态) | 控件后置内容 |
| prefix | VNode (动态) | 控件前置内容 |
| extra | VNode (动态) | 额外提示信息 |
动态计算 (ComputedField)
大多数属性支持静态值或动态回调:
ts
// 静态值
{ show: false }
// 动态回调 — 根据表单其他字段的值决定
{ show: (formData) => formData.type === 'A' }
// props 也支持动态
{ props: (formData) => ({ placeholder: `当前值: ${formData.name}` }) }校验规则 (Rule)
ts
{
required?: boolean // 是否必填
message?: string // 错误提示
trigger?: string // 触发方式: 'blur' | 'change'
pattern?: RegExp // 正则
type?: string // 数据类型: 'email', 'number'
validator?: Function // 自定义校验函数
}预置组件类型
| type | 说明 |
|---|---|
| (空) | 默认为 input-plus 文本输入 |
el-input / el-input-number | Element Plus 输入框 |
el-select | Element Plus 下拉选择 |
el-switch | 开关 |
el-date-picker | 日期选择器 |
el-radio-group | 单选组 |
el-checkbox-group | 多选组 |
data-picker | 增强选择器 |
data-text | 纯文本显示 |
file-upload | 文件上传 |
input-plus | 增强输入框 |
form-edit-table | 可编辑表格 |
form-edit-list | 可编辑列表 |
实例方法
通过 ref 调用:
| 方法 | 说明 |
|---|---|
validate() | 校验表单,返回 Promise |
resetFields() | 重置表单到初始值 |
clearValidate() | 移除校验结果 |
getFieldsValue() | 获取当前表单值 |
scrollToField(prop) | 滚动到指定字段 |
useFormLayout — 弹窗表单
useFormLayout 是一个函数式弹窗/抽屉钩子,可以在 JS 逻辑中直接唤起包含 DataForm 或自定义内容的弹窗。
ts
import { useFormLayout } from 'yoyoo-ui'
const { open } = useFormLayout()
// 打开一个表单弹窗
open({
title: '编辑用户',
type: 'modal', // 或 'drawer'
size: 'md',
form: {
model: { name: '', age: 18 },
columns: [
{ field: 'name', label: '用户名', required: true },
{ field: 'age', label: '年龄', type: 'el-input-number' },
],
},
onConfirm: async ({ form }) => {
console.log('表单数据:', form)
await saveUser(form)
},
})LayoutOptions
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| title | string | '标题' | 弹窗标题 |
| type | 'modal' | 'drawer' | 'modal' | 展现形式 |
| size | 'sm' | 'md' | 'l' | 'lg' | 'xlg' | 'md' | 尺寸(对应 400/800/1000/1200/1400px) |
| form | FormProps | - | DataForm 配置 |
| content | VNode | Component | - | 自定义内容组件 |
| showButton | boolean | true | 是否显示底部按钮 |
| buttons | ButtonProps[] | - | 自定义按钮组 |
| onConfirm | (data) => Promise | void | - | 确认回调 |
| onCancel | () => void | - | 取消回调 |
| props | Object | {} | 透传给 ElDialog/ElDrawer 的 props |