element-easy-form
Version:
vue3.0 的自定义表单,基于element-Plus
559 lines (558 loc) • 18 kB
TypeScript
/**
* ========================================
* 动态表单核心类型定义
* ========================================
* 本文件定义了基于 JSON Schema 的动态表单渲染引擎的核心类型。
* 通过这些类型配置,可以实现无代码/低代码的表单构建和渲染。
*
* 适用场景:
* - 可视化表单设计器:用户通过拖拽组件构建表单,生成 JSON 配置
* - 动态表单渲染:根据 JSON 配置自动渲染表单,支持复杂的表单交互
* - 多语言支持:字段标签支持多语言切换
* - 复杂表单控制:基于其他字段值动态显示/隐藏字段
*/
/**
* 表单项动态显示/隐藏控制配置
*
* 用于定义表单项的显示逻辑,可以根据其他表单字段的值或自定义函数来控制当前字段是否显示。
*
* @example
* // 示例1: 简单控制 - 始终显示
* {
* "matchPattern": "&&",
* "type": "select",
* "value": false, // false=显示, true=隐藏
* "dataJs": "function hidden(config,data){\n return false;\n}"
* }
*
* @example
* // 示例2: 基于其他字段控制 - 当 userType='admin' 时隐藏该字段
* {
* "matchPattern": "&&",
* "type": "function",
* "value": false,
* "dataJs": "function hidden(config,data){\n // data 是当前表单的所有字段值\n return data.userType === 'admin';\n}"
* }
*
* @example
* // 示例3: 多条件组合 - 当 age > 18 且 city='beijing' 时显示
* {
* "matchPattern": "&&", // && 表示所有条件都满足, || 表示任一条件满足
* "type": "function",
* "value": true,
* "dataJs": "function hidden(config,data){\n return data.age > 18 && data.city === 'beijing';\n}"
* }
*/
export interface BooleanDragFormData {
/**
* 逻辑匹配模式
* - "&&": AND 逻辑,所有条件都满足时生效
* - "||": OR 逻辑,任一条件满足时生效
* 用于多个条件组合时使用
*/
matchPattern: string;
/**
* 编辑器类型
* - "select": 使用下拉选择器配置(简单模式)
* - "function": 使用代码编辑器编写自定义函数(高级模式)
*/
type: string;
/**
* 是否隐藏字段
* - false: 显示该字段(默认值)
* - true: 隐藏该字段
* 实际显示/隐藏状态由 dataJs 函数的返回值决定
*/
value: Boolean;
/**
* 编辑器数据(可选)
* 当 type="select" 时使用,提供可选择的条件列表
* 通常用于可视化配置时预设一些常用条件
*
* @example
* [{
* label: "用户类型为管理员",
* value: "data.userType === 'admin'"
* }]
*/
dataSelect?: any[];
/**
* 显示/隐藏控制函数
* 可以是字符串形式的函数代码,也可以是直接传入函数对象
*
* @param config - 当前字段的 FormItemJSON 配置对象
* @param data - 表单的所有字段数据对象 { [prop: string]: any }
* @returns boolean - true 表示隐藏, false 表示显示
*
* @example 函数签名
* function hidden(config: FormItemJSON, data: Record<string, any>): boolean {
* // config.prop: 当前字段名
* // data: 整个表单的数据对象
* // 返回 true 隐藏, false 显示
* return data.someField === 'someValue';
* }
*/
dataJs: string | Function;
}
/**
* 表单项配置接口
*
* 这是动态表单的核心数据结构,每个表单字段对应一个 FormItemJSON 对象。
* 通过配置这个对象,可以完全定义一个表单字段的行为、样式、验证规则和交互逻辑。
*
* 使用场景:
* 1. 作为拖拽表单设计器的组件配置(schema 数组中的元素)
* 2. 直接用于 ElementEasyForm 组件的 formJson.schema 属性
* 3. 支持嵌套结构(如 ElSelect 包含 ElOption 子组件)
*
* @example 基础文本输入框
* {
* "label": "用户名",
* "prop": "username",
* "componentName": "ElInput",
* "attrs": {
* "type": "text",
* "placeholder": "请输入用户名"
* },
* "rules": [{
* "required": true,
* "message": "用户名不能为空"
* }]
* }
*
* @example 下拉选择框(带子组件)
* {
* "label": "城市",
* "prop": "city",
* "componentName": "ElSelect",
* "attrs": {
* "placeholder": "请选择城市",
* "clearable": true
* },
* "children": [
* { "componentName": "ElOption", "value": "bj", "label": "北京" },
* { "componentName": "ElOption", "value": "sh", "label": "上海" }
* ]
* }
*
* @example 带动态显示控制的字段
* {
* "label": "管理员密码",
* "prop": "adminPassword",
* "componentName": "ElInput",
* "attrs": { "type": "password", "show-password": true },
* "hidden": {
* "matchPattern": "&&",
* "type": "function",
* "value": true,
* "dataJs": "function hidden(config,data){\n return data.userType !== 'admin';\n}"
* }
* }
*/
export interface FormItemJSON {
/**
* 表单标签文本
* 显示在输入框上方的提示文字
* - 可选字段,如果不提供则不显示标签
* - 支持多语言(通过 locale 配置)
*
* @example "用户名"
* @example 支持多语言: 从 locale.dataList 中查找对应语言的翻译
*/
label?: string;
/**
* 字段唯一标识符
* - 必填字段,用于标识表单字段
* - 对应 model 对象中的 key
* - 必须在整个 schema 中唯一
*
* 使用场景:
* 1. 表单提交时的字段名
* 2. 表单验证时引用字段
* 3. hidden 函数中访问其他字段的值
* 4. 动态表单渲染的数据绑定路径
*
* @example "username"
* @example "user.age" (支持嵌套路径)
*/
prop: string;
/**
* 自定义渲染函数(高级功能)
* 用于完全自定义字段渲染逻辑,替代 componentName 的默认渲染
* - 接收 JSX 格式的渲染函数
* - 适用于需要高度定制化场景
*
* @param config - 当前字段的配置对象
* @param model - 表单数据模型
* @returns JSX 元素或 VNode
*
* 使用示例:
* render: (config, model) => (
* <div>
* <span>自定义内容: {model[config.prop]}</span>
* </div>
* )
*/
render?: any;
/**
* 组件名称
* 指定使用哪个 Vue 组件来渲染该表单项
* - 组件需要全局注册或在父组件中局部注册
* - 支持 Element Plus 的所有组件和自定义组件
* - 如果提供了 render,则忽略此属性
*
* 常用组件:
* - ElInput: 输入框
* - ElInputNumber: 数字输入框
* - ElSelect: 下拉选择
* - ElRadioGroup: 单选组
* - ElCheckboxGroup: 多选组
* - ElDatePicker: 日期选择器
* - ElSwitch: 开关
* - 等等...
*
* @example "ElInput"
* @example "CustomField" (自定义组件名)
*/
componentName?: string;
/**
* FormItem 容器属性
* 传递给 Element Plus <el-form-item> 组件的属性
* 用于控制表单项容器本身的行为和样式
*
* 常用属性:
* - labelWidth: 标签宽度,如 "80px"
* - required: 是否必填,与 rules 配合使用
* - error: 错误提示信息
* - showMessage: 是否显示校验错误信息
* - inline: 是否为行内表单模式
*
* @example { "labelWidth": "100px" }
* @example { "required": true }
*/
formItemAttrs?: any;
/**
* 组件属性配置
* 传递给实际渲染组件(如 ElInput)的属性
* 用于控制组件的行为、样式和交互
*
* 不同组件支持的属性不同,需参考对应组件的文档
*
* ElInput 常用属性:
* - type: 输入框类型(text/password/textarea/number)
* - placeholder: 占位符文本
* - disabled: 是否禁用
* - readonly: 是否只读
* - maxlength: 最大输入长度
* - show-password: 是否显示密码切换图标
*
* ElSelect 常用属性:
* - placeholder: 占位符
* - clearable: 是否可清空
* - multiple: 是否多选
* - filterable: 是否可搜索
*
* @example ElInput: { "type": "text", "placeholder": "请输入" }
* @example ElSwitch: { "active-color": "#13ce66" }
*/
attrs?: any;
/**
* 自定义标签渲染函数
* 用于完全自定义标签部分的内容
* - 接收 JSX 格式的渲染函数
* - 与 label 属性二选一使用
*
* @param config - 当前字段的配置对象
* @returns JSX 元素或 VNode
*
* 使用场景:
* - 标签中需要包含图标、链接等复杂内容
* - 标签需要根据条件动态变化
*
* @example
* renderLabel: (config) => (
* <div>
* <el-icon><user /></el-icon>
* {config.label}
* </div>
* )
*/
renderLabel?: any;
/**
* 栅格布局属性
* 传递给 Element Plus <el-col> 组件的属性
* 用于控制表单项在栅格系统中的占位和布局
*
* 常用属性:
* - span: 栅格占位格数(总共24格),如 12 表示占一半宽度
* - offset: 栅格左侧间隔格数
* - push: 栅格向右移动格数
* - pull: 栅格向左移动格数
* - xs/sm/md/lg/xl: 响应式断点配置
*
* @example { "span": 12 } // 占50%宽度
* @example { "span": 8, "offset": 4 } // 占1/3宽度,右侧间隔1/6
*/
colAttrs?: any;
/**
* 组件事件配置
* 定义组件支持的事件及其处理函数
* - 数组格式,每个元素代表一个事件配置
* - 事件函数以字符串形式存储,运行时通过 eval 或 Function 构造器执行
*
* 事件配置对象结构:
* - prop: 事件名称(如 change、blur、focus)
* - label: 事件描述
* - defaultValue: 事件处理函数代码字符串
* - componentName: 固定为 "ElFunctionEvent"
*
* @example 输入框事件
* events: [
* {
* "prop": "blur",
* "label": "当失去焦点时触发",
* "defaultValue": "function blur(config,data,event){\n console.log('blur');\n}",
* "componentName": "ElFunctionEvent"
* },
* {
* "prop": "change",
* "label": "值改变时触发",
* "defaultValue": "function change(config, data, value){\n console.log(value);\n}",
* "componentName": "ElFunctionEvent"
* }
* ]
*
* 事件函数参数说明:
* - config: 当前字段的 FormItemJSON 配置
* - data: 整个表单的数据模型
* - event/value: 事件对象或新值(根据事件类型不同)
*/
events?: any;
/**
* 字段默认值
* 表单初始化时该字段的默认值
* - 可选字段
* - 值的类型需与组件类型匹配
*
* @example 字符串: ""
* @example 数字: 0
* @example 数组: [] (用于多选组件)
* @example 布尔: false (用于开关组件)
*/
defaultValue?: any;
/**
* 动态显示/隐藏控制
* 配置该字段的显示逻辑
* - 可选字段
* - 不配置则始终显示
* - 参见 BooleanDragFormData 接口说明
*
* @example 简单隐藏
* hidden: {
* "matchPattern": "&&",
* "type": "function",
* "value": true,
* "dataJs": "function hidden(config,data){ return false; }"
* }
*
* @example 条件显示:当 age > 18 时显示
* hidden: {
* "matchPattern": "&&",
* "type": "function",
* "value": false,
* "dataJs": "function hidden(config,data){ return data.age > 18; }"
* }
*/
hidden?: BooleanDragFormData;
/**
* 子组件配置
* 某些组件需要嵌套子组件来定义其选项或内容
* - 可选字段
* - 子组件也遵循 FormItemJSON 结构
*
* 常用场景:
* 1. ElSelect: 子项为 ElOption,定义可选项
* 2. ElRadioGroup: 子项为 ElRadio,定义单选项
* 3. ElCheckboxGroup: 子项为 ElCheckbox,定义多选项
* 4. ElCascader: 子项为级联选项
* 5. ElRow: 子项为 ElCol,定义栅格布局
* 6. ElDragTable: 子项为表格列配置
*
* @example ElSelect 的 children
* children: [
* { "componentName": "ElOption", "value": "bj", "label": "北京" },
* { "componentName": "ElOption", "value": "sh", "label": "上海" }
* ]
*
* @example ElRadioGroup 的 children
* children: [
* { "componentName": "ElRadio", "value": "male", "label": "男" },
* { "componentName": "ElRadio", "value": "female", "label": "女" }
* ]
*/
children?: any[];
/**
* 表单验证规则
* 定义字段的校验规则
* - 数组格式,可配置多个规则
* - 符合 Element Plus 验证规则格式
*
* 常用规则属性:
* - required: 是否必填
* - message: 错误提示信息
* - trigger: 触发时机('blur'/'change')
* - min/max: 最小/最大长度
* - pattern: 正则表达式
* - validator: 自定义验证函数
*
* @example 基础验证
* rules: [{
* "required": true,
* "message": "用户名不能为空",
* "trigger": "blur"
* }]
*
* @example 多个验证规则
* rules: [{
* "required": true,
* "message": "手机号不能为空"
* }, {
* "pattern": /^1[3-9]\d{9}$/,
* "message": "请输入正确的手机号"
* }]
*
* @example 自定义验证
* rules: [{
* "validator": (rule, value, callback) => {
* if (value !== '123456') {
* callback(new Error('密码错误'));
* } else {
* callback();
* }
* }
* }]
*/
rules?: any;
}
/**
* 完整表单配置接口
*
* 这是动态表单的顶级配置对象,包含了渲染整个表单所需的所有信息。
* 通常作为 ElementEasyForm 或 dragForm 组件的 v-model 绑定值。
*
* @example 完整的表单配置
* {
* "language": "zh",
* "formType": "drag-form",
* "schema": [...],
* "model": { "username": "", "age": "" },
* "formAttrs": { "disabled": false },
* "rowAttrs": { "gutter": 20 },
* "locale": {...}
* }
*/
export interface FormJSON {
/**
* 表单结构配置数组
* 定义了表单包含的所有字段及其配置
* - 数组中的每个元素对应一个表单项
* - 数组顺序决定了字段在表单中的显示顺序
*
* 使用场景:
* 1. 拖拽表单设计器:用户从左侧拖拽组件,schema 实时更新
* 2. 直接渲染:通过 JSON 配置定义表单结构
* 3. 动态生成:根据后端返回的数据生成 schema
*
* @example 简单表单
* schema: [
* { "label": "用户名", "prop": "username", "componentName": "ElInput" },
* { "label": "年龄", "prop": "age", "componentName": "ElInputNumber" }
* ]
*
* @example 带布局的表单
* schema: [
* {
* "componentName": "ElRow",
* "attrs": { "gutter": 20 },
* "children": [
* { "componentName": "ElCol", "colAttrs": { "span": 12 }, "children": [...] },
* { "componentName": "ElCol", "colAttrs": { "span": 12 }, "children": [...] }
* ]
* }
* ]
*/
schema: Array<FormItemJSON>;
/**
* 表单数据模型
* 存储表单所有字段的当前值
* - 对象的 key 对应 schema 中各字段的 prop
* - 组件的 v-model 绑定到此对象
* - 表单提交时使用此对象
*
* 数据同步:
* - 用户输入时自动更新 model 中对应的值
* - 可以通过外部修改 model 值来改变表单显示
* - watch 监听 model 变化可实现联动效果
*
* @example 初始空数据
* model: {
* "username": "",
* "password": "",
* "age": null
* }
*
* @example 带默认值
* model: {
* "username": "admin",
* "remember": true,
* "city": "bj"
* }
*/
model: any;
/**
* 表单容器属性
* 传递给 Element Plus <el-form> 组件的属性
* 用于控制整个表单的行为
*
* 常用属性:
* - disabled: 是否禁用整个表单
* - labelPosition: 标签位置('left'/'right'/'top')
* - labelWidth: 标签宽度
* - labelSuffix: 标签后缀
* - hideRequiredAsterisk: 是否隐藏必填星号
* - showMessage: 是否显示校验错误信息
* - inlineMessage: 是否以行内形式展示校验信息
* - statusIcon: 是否在输入框中显示校验结果反馈图标
* - validateOnRuleChange: 是否在 rules 属性改变后立即触发一次验证
* - size: 表单尺寸('large'/'default'/'small')
*
* @example
* formAttrs: {
* "labelPosition": "top",
* "labelWidth": "100px",
* "disabled": false,
* "statusIcon": true
* }
*/
formAttrs: any;
/**
* 行布局属性
* 用于栅格布局系统中的行级配置
* - 传递给 Element Plus <el-row> 组件
* - 主要在复杂布局中使用
*
* 常用属性:
* - gutter: 栅格间隔,如 20
* - type: 布局模式('flex')
* - justify: flex 布局下的水平排列方式('start'/'center'/'end'/'space-between' 等)
* - align: flex 布局下的垂直排列方式('top'/'middle'/'bottom')
*
* @example
* rowAttrs: {
* "gutter": 20,
* "type": "flex",
* "justify": "center"
* }
*/
rowAttrs: any;
}