element-easy-form
Version:
vue3.0 的自定义表单,基于element-Plus
476 lines (474 loc) • 15.5 kB
TypeScript
import { FormItemJSON } from '../element-easy-form';
import { AttrType, ComponentType } from './enum';
import { WatchOptions } from 'vue';
/**
* ========================================
* 拖拽表单设计器类型定义
* ========================================
* 本文件定义了用于可视化表单设计器的类型和工厂函数。
* DragFormType 是设计器中每个组件的数据结构,扩展了基础的 FormItemJSON。
*
* 与 FormItemJSON 的区别:
* - FormItemJSON: 运行时表单渲染用的轻量级配置
* - DragFormType: 设计器用的增强配置,包含额外的设计时信息(id、active、attrsJson等)
*/
/**
* Watch 监听器配置接口
*
* 用于在设计器中为组件添加响应式监听
* 监听某个属性的变化并执行相应操作
*
* @example 监听 prop 变化
* {
* "prop": "attrs.disabled",
* "immediate": true,
* "handler": (value, children) => {
* console.log('disabled 变为:', value);
* }
* }
*
* @example 监听并联动子组件
* {
* "prop": "attrs.value",
* "handler": (value, children) => {
* children.forEach(child => {
* child.attrs.placeholder = value;
* });
* }
* }
*/
interface WatchHandler {
/**
* 监听的属性路径
* 支持点号访问嵌套属性
*
* @example "attrs.disabled" - 监听组件的 disabled 属性
* @example "attrs.value" - 监听组件的 value 属性
* @example "attrsJson[0].defaultValue" - 监听属性配置数组中某项的默认值
*/
prop: string;
/**
* 是否立即执行一次监听器
* - true: 组件初始化时立即调用 handler
* - false: 只在属性变化时调用
*
* 默认: false
*/
immediate?: boolean;
/**
* Vue watch 配置选项
* 用于精细控制监听行为
*
* 可选配置:
* - deep: 是否深度监听对象/数组
* - flush: 回调的触发时机('pre'/'post'/'sync')
*
* @example { "deep": true } - 深度监听对象变化
* @example { "deep": false, "flush": "post" } - 不深度监听,回调在 DOM 更新后触发
*/
options?: WatchOptions;
/**
* 属性变化时的回调函数
* 在监听的属性值改变时执行
*
* @param value - 属性的新值
* @param children - 组件的子组件数组(可选)
*
* 使用场景:
* 1. 联动更新子组件属性
* 2. 根据某个属性值的变化执行自定义逻辑
* 3. 属性间的复杂联动关系
*
* @example 简单日志输出
* handler: (value) => {
* console.log('值变为:', value);
* }
*
* @example 联动更新子组件
* handler: (value, children) => {
* if (children) {
* children.forEach(child => {
* if (child.componentName === 'ElOption') {
* child.attrs.disabled = value;
* }
* });
* }
* }
*/
handler: (value: any, children?: any[]) => void;
}
/**
* 拖拽表单组件类型
*
* 扩展自 FormItemJSON,在运行时表单配置的基础上增加了设计器所需的属性
* 用于拖拽表单设计器中每个组件的内部表示
*
* 继承自 FormItemJSON 的属性:
* - label, prop, componentName, attrs, events, defaultValue, hidden, children, rules 等
*
* 新增的设计器专属属性:
* - id: 组件唯一标识(设计器中生成)
* - type: 组件分类(布局/组件/表单项)
* - attrsJson: 属性配置元数据(用于生成右侧属性面板)
* - title: 设计器中的显示标题
* - active: 当前选中状态
* - formType: 支持的表单类型
* - parentId: 父组件 ID
* - watch: 属性监听配置
*
* 使用场景:
* 1. 左侧组件列表:定义可拖拽的组件模板
* 2. 中间画布:定义已拖入的组件实例
* 3. 右侧属性面板:通过 attrsJson 生成属性编辑表单
* 4. 拖拽交互:通过 id、parentId 管理组件树结构
*
* @example 设计器中的输入框组件
* {
* // 继承自 FormItemJSON 的运行时属性
* "label": "用户名",
* "prop": "username",
* "componentName": "ElInput",
* "attrs": { "type": "text", "placeholder": "请输入" },
*
* // 设计器专属属性
* "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
* "title": "输入框",
* "type": "COMPONENT",
* "active": false,
* "formType": "all",
* "parentId": "parent-row-id",
*
* // 属性配置元数据(用于生成右侧属性编辑面板)
* "attrsJson": [
* {
* "label": "类型",
* "prop": "attrs.type",
* "componentName": "ElSelect",
* "type": "COMPONENT",
* "defaultValue": "text",
* "children": [
* { "componentName": "ElOption", "value": "text", "label": "文本" },
* { "componentName": "ElOption", "value": "password", "label": "密码" }
* ]
* },
* {
* "label": "占位符",
* "prop": "attrs.placeholder",
* "componentName": "ElInput",
* "type": "COMPONENT",
* "defaultValue": "请输入"
* }
* ],
*
* // 属性监听器
* "watch": [
* {
* "prop": "attrs.type",
* "handler": (value) => {
* console.log('输入框类型变为:', value);
* }
* }
* ]
* }
*
* @example 设计器中的栅格列组件
* {
* "id": "col-1",
* "title": "列",
* "componentName": "ElCol",
* "type": "LAYOUT",
* "attrs": { "span": 12 },
* "parentId": "row-1",
* "children": [...],
* "attrsJson": [...]
* }
*/
export interface DragFormType extends FormItemJSON {
/**
* 组件唯一标识符
* 设计器中每个组件实例的唯一 ID
* - 使用 UUID 生成
* - 用于在拖拽操作中识别组件
* - 用于建立父子关系(parentId)
* - 用于选中组件时的状态管理
*
* 使用场景:
* 1. 拖拽时克隆组件生成新 ID
* 2. 右侧属性面板选中组件时通过 id 查找
* 3. 删除组件时通过 id 从数组中移除
* 4. 导出 JSON 时保留组件层级关系
*
* 注意:
* - 生成最终表单 JSON 时,运行时不需要这些 ID
* - 只在设计器中使用
*
* @example "550e8400-e29b-41d4-a716-446655440000"
*/
id?: string;
/**
* 组件分类类型
* 标识组件在设计器中的分类和用途
*
* 可选值(参考 AttrType 枚举):
* - "COMPONENT": 表单组件(输入框、选择器等)
* - "LAYOUT": 布局组件(ElRow、ElCol)
* - "FORMITEM": 表单项容器属性
*
* 使用场景:
* 1. 过滤左侧组件列表(按 formType 显示不同类型)
* 2. 控制拖拽规则(某些组件只能拖入特定容器)
* 3. 右侧属性面板渲染不同的表单项
*
* @example "COMPONENT" - 表单字段组件
* @example "LAYOUT" - 栅格布局组件
* @example "FORMITEM" - FormItem 属性配置
*/
type?: string;
/**
* 属性配置元数据数组
* 定义了该组件在右侧属性面板中可配置的所有属性
* - 数组中每个元素是一个 FormItemJSON
* - 用于动态生成属性编辑表单
* - 与 attrs 是不同的概念:attrs 是组件本身的属性,attrsJson 是如何配置这些属性的元数据
*
* 属性配置项结构:
* - prop: 要配置的组件属性路径(如 "attrs.type")
* - label: 属性显示名称
* - componentName: 用于编辑该属性的组件(ElInput、ElSelect 等)
* - defaultValue: 默认值
* - children: 对于需要子组件的属性(如 ElSelect 需要 ElOption)
* - type: 属性分类(COMPONENT/FORMITEM/LAYOUT)
*
* 使用场景:
* 1. 设计器右侧属性面板自动生成
* 2. 可视化配置组件的所有可配置属性
* 3. 属性面板的表单验证
*
* @example ElInput 的 attrsJson
* attrsJson: [
* {
* "label": "类型",
* "prop": "attrs.type",
* "type": "COMPONENT",
* "componentName": "ElSelect",
* "defaultValue": "text",
* "children": [
* { "componentName": "ElOption", "value": "text", "label": "文本" },
* { "componentName": "ElOption", "value": "password", "label": "密码" }
* ]
* },
* {
* "label": "占位符",
* "prop": "attrs.placeholder",
* "type": "COMPONENT",
* "componentName": "ElInput",
* "defaultValue": "请输入"
* },
* {
* "label": "是否禁用",
* "prop": "attrs.disabled",
* "type": "COMPONENT",
* "componentName": "ElSwitch",
* "defaultValue": false
* }
* ]
*
* @example ElRow 的 attrsJson(配置列的 span)
* attrsJson: [
* {
* "label": "栅格列配置",
* "prop": "attrsJson",
* "type": "FORMITEM",
* "componentName": "ElRowAttrs",
* "defaultValue": [
* { "attrs": { "span": 12 } },
* { "attrs": { "span": 12 } }
* ]
* }
* ]
*/
attrsJson?: FormItemJSON[];
/**
* 组件显示标题
* 在设计器中展示给用户的组件名称
* - 固定值,用户不可更改
* - 用于左侧组件列表按钮的文字
* - 用于中间画布组件的标题显示
* - 不同于 label(label 是表单字段的标签,title 是设计器中的组件名)
*
* @example "输入框"
* @example "下拉选择"
* @example "日期选择器"
* @example "栅格行"
*/
title?: string;
/**
* 当前激活状态
* 标识组件是否被用户选中
* - true: 组件被选中(在画布上高亮,右侧显示属性面板)
* - false: 组件未被选中
*
* 使用场景:
* 1. 点击画布中的组件,设置 active = true
* 2. 点击画布空白处,清除所有组件的 active 状态
* 3. 根据 active 状态渲染高亮样式(边框、阴影等)
* 4. 右侧属性面板根据 active 组件显示对应属性
*
* 注意:
* - 同一时间只能有一个组件处于 active 状态
* - 切换组件选中时需要更新其他组件的 active 为 false
* - 最终导出的 JSON 中不包含此字段
*
* @example 被选中的组件: { "active": true, ... }
* @example 未选中的组件: { "active": false, ... }
*/
active?: boolean;
/**
* 支持的表单类型
* 标识该组件在哪种表单模式下可用
*
* 可选值(参考 JSONType 枚举):
* - "drag-form": 仅在拖拽表单模式下可用
* - "element-easy-form": 仅在二开表单模式下可用
* - "all": 在两种模式下都可用
*
* 使用场景:
* 1. 切换表单类型时过滤左侧组件列表
* 2. 控制不同模式下显示不同的可用组件
*
* @example "all" - 两种表单类型都支持
* @example "drag-form" - 仅拖拽表单模式支持
* @example "element-easy-form" - 仅二开表单模式支持
*/
formType?: string;
/**
* 父组件唯一标识符
* 标识当前组件的父组件,用于构建组件树结构
* - 对于根级组件,parentId 可能为空
* - 对于子组件,parentId 指向其父组件的 id
*
* 使用场景:
* 1. 建立组件层级关系(树形结构)
* 2. 拖拽时判断组件是否可以放置到某个容器内
* 3. 删除父组件时同时删除所有子组件
* 4. 查找组件的父级或兄弟组件
* 5. 导出 JSON 时重建嵌套结构
*
* @example 顶层组件: parentId = undefined 或 ""
* @example ElOption: parentId = "el-select-id"
* @example ElCol: parentId = "el-row-id"
*/
parentId?: string;
/**
* 属性监听器配置
* 用于监听组件自身属性的变化并执行回调
* - 可以配置单个监听器或监听器数组
* - 监听器在属性值变化时自动触发
*
* 使用场景:
* 1. 联动更新子组件的属性(如改变 Select 的值,影响 Option 的状态)
* 2. 属性之间的依赖关系(如改变某个属性,自动调整其他属性)
* 3. 属性变化时的自定义业务逻辑
* 4. 组件初始化时的默认设置(使用 immediate: true)
*
* @example 监听单个属性
* watch: {
* "prop": "attrs.disabled",
* "immediate": true,
* "handler": (value) => {
* console.log('disabled 变为:', value);
* }
* }
*
* @example 监听多个属性(数组形式)
* watch: [
* {
* "prop": "attrs.type",
* "handler": (value) => {
* // 输入框类型改变时的处理
* }
* },
* {
* "prop": "attrs.placeholder",
* "handler": (value) => {
* // 占位符改变时的处理
* }
* }
* ]
*
* @example 联动更新子组件
* watch: {
* "prop": "attrs.value",
* "handler": (value, children) => {
* if (children) {
* children.forEach(child => {
* child.attrs.label = `选项 ${value}`;
* });
* }
* }
* }
*/
watch?: WatchHandler | WatchHandler[];
}
/**
* 创建 ElCol 栅格列数据工厂函数
*
* 生成 ElCol 组件在设计器中的标准配置
* 常用于 ElRow 的子组件创建
*
* @param span - 栅格占位格数,默认使用 SPANDEFAULT
* @param parentId - 父组件 ID,默认为空字符串
*
* @returns DragFormType - ElCol 组件配置对象
*
* @example 创建一个占12格的列
* const col1 = ElColDragFormData(12, "row-1");
* // 结果: { title: "列", type: "LAYOUT", componentName: "ElCol", attrs: { span: 12 }, ... }
*
* @example 创建一个占8格的列
* const col2 = ElColDragFormData(8, "row-1");
* // 结果: { title: "列", type: "LAYOUT", componentName: "ElCol", attrs: { span: 8 }, ... }
*
* @example 使用默认 span
* const col3 = ElColDragFormData(undefined, "row-1");
* // 结果: { title: "列", type: "LAYOUT", componentName: "ElCol", attrs: { span: SPANDEFAULT }, ... }
*/
export declare const ElColDragFormData: (span?: number, parentId?: string) => {
title: string;
type: AttrType;
componentName: ComponentType;
attrs: {
span: number;
};
parentId: string;
children: never[];
attrsJson: DragFormType[];
};
/**
* 创建表格列数据工厂函数
*
* 生成 ElDragTable 组件的列配置
* 用于动态表格的列定义
*
* @param span - (未使用)保留参数,未来可能扩展
*
* @returns DragFormType - 表格列配置对象
*
* @example 创建一个表格列
* const column = ElTableColumnsData();
* // 结果: { title: "列", type: "COMPONENT", componentName: "ElDragTableColumns", ... }
*
* 注意:
* - 此函数返回的列配置是一个模板
* - 实际使用时需要设置 prop、label 等属性
* - 表格组件的 children 数组包含多个列配置
*/
export declare const ElTableColumnsData: (span?: number) => {
title: string;
type: AttrType;
componentName: ComponentType;
attrs: {};
children: never[];
attrsJson: never[];
};
export {};