动态表单组件ReForm

动态表单组件ReForm

组件实现基于 Vue3 + Element Plus + Typescript,同时引用 vueUse + lodash-es + tailwindCss (不影响功能,可忽略)

基于ElForm封装的动态表单组件,可通过配置对象自动渲染表单内容,可配置表单内容、表单校验规则、表单联动、折叠表单、多列表单,满足大部分表单应用场景。

表单内容组件基于动态组件(component)渲染,因此,你可以随意配置想要的表单控件(全局注册),同时也支持通过插槽(slot)配置自定义表单控件。

内置几个特殊表单控件,如多行文本框(textarea/el-textarea)、下拉列表(el-select)、单选组(el-radio-group)、多选组(el-checkbox-group),后面三个有固定关联子组件,相比其他组件有增加几个配置字段,需要特别留意,若是还有其他相似的组件,目前建议通过插槽slot走自定义渲染。

思路

基于ElFormItem的属性增加渲染组件说明字段,整合成一个动态ElFormItem渲染说明对象,通过v-for循环渲染实现一个简单的表单动态渲染。

考虑到 分组功能,使用嵌套数据格式进行渲染,动态渲染中会存在组件的嵌套渲染。

整体设计:

  • Form:表单容器,处理表单配置配置,收集数据和校验规则,通过 renderFormItem 组件渲染同级表单项
  • renderFormItems:同级表单项渲染,调用v-for遍历表单配置进行单个表单项 renderFormItem 的渲染,当遇到分组配置,需要嵌套调用 renderFormItems 渲染分组表单内容
  • renderFormItem:渲染单个表单项,处理表单控件渲染,控件属性、事件等问题

难点

  • 插槽渲染:通过动态插槽渲染方式
  • 数据绑定:需要自行挂载 modelValue + update:modelValue

基础应用

通过 items 字段配置表单,每个配置项表示一个表单字段,ReForm会基于表单配置自动初始化表单数据,可以通过 v-model 实现表单数据的双向绑定,不需要特殊处理表单数据的话可以完全忽略,直接在 submit 事件中通过第一个参数获取当前表单值进行接口提交处理。
在这里插入图片描述

const formItems = ref([
  {
    label: "ID",
    field: "id",
    defaultValue: "just text content",
    type: "text",
    customClass: "is-required" // 通过样式类展示必填ico,不直接绑定required属性,会有校验问题
  },
  {
    label: "Name",
    field: "name",
    defaultValue: "",
    comp: "el-input",
    // labelSlot: "name-label", 默认字段标签名插槽命名规则 [field]-label,也可以自定义
    tooltip: "这是tooltip",
    props: {
      clearable: true
    },
    rules: [{ required: true, message: "不能为空" }]
  },
  {
    label: "Age",
    field: "age",
    comp: "el-input",
    props: {
      type: "number",
      min: 1,
      max: 9999
    },
    events: {
      focus: handleNumberFocus,
      blur: handleNumberBlur
    }
  },
  {
    label: "Remark",
    field: "remark",
    comp: "el-textarea",
    props: {
      rows: 4
    }
  },
  {
    label: "Birthday",
    field: "birthday",
    comp: "el-date-picker",
    tooltip: "这是tooltip",
    props: {
      type: "date",
      format: "YYYY/MM/DD",
      class: "w-full"
    }
  },
  {
    label: "Subject",
    field: "subject",
    comp: "el-select",
    tooltip: "这是tooltip",
    tips: "这是显眼的tips",
    options: [
      {
        label: "Subject1",
        value: "1"
      },
      {
        label: "Subject2",
        value: "2"
      },
      {
        label: "Subject3",
        value: "3"
      }
    ],
    rules: [{ required: true, message: "不能为空" }],
    props: {
      clearable: true
    }
  },
  {
    label: "Hobby",
    field: "hobby",
    comp: "el-checkbox-group",
    labelKey: "name",
    valueKey: "id",
    options: [
      {
        name: "hobby1",
        id: "1"
      },
      {
        name: "hobby2",
        id: "2"
      },
      {
        name: "hobby3",
        id: "3"
      }
    ],
    defaultValue: ["1"],
    props: {
      clearable: true
    }
  },
  {
    label: "Marry",
    field: "marry",
    comp: "el-radio-group",
    options: [
      {
        label: "married",
        value: "1"
      },
      {
        label: "none",
        value: "2"
      }
    ],
    defaultValue: "2",
    props: {
      clearable: true
    }
  }
]);

查看 /demo/form/basic.md

只读展示

设置 editable 字段为 false,表单会按只读模式展示,可用于一些详情页展示,与 disabled 不同的是,disabled 只是禁用表单控件,不影响表单内容。

在这里插入图片描述

查看 /demo/form/readonly.md

响应网格布局

ReForm可以通过设置 cols 字段指定响应网格数量,默认为 1,每个表单配置项可以通过 span 设置网格大小,默认为 1

在这里插入图片描述

查看 /demo/form/grid.md

分组表单项

表单配置项允许通过 type=group 指定当前配置项为分组配置项,需要指定 children 字段配置组内的表单配置项,同 items 配置项一致,正常分组不超过两级,也不建议超过两级。

在这里插入图片描述
在这里插入图片描述

查看 /demo/form/group.md

字段联动/隐藏

表单配置项允许通过 visible 字段控制表单项的隐藏,也支持配置联动规则由ReForm控制隐藏。

在这里插入图片描述

在这里插入图片描述

查看 /demo/form/relation.md

自定义表单控件

每个配置项默认支持两种种插槽 labelSlotslotslot 用于自定义控件,默认 [field]-controllabelSlot 用于自定义标签,默认 [field]-label。labelSlot指定插槽为命名插槽,slot指定插槽为作用域插槽,带有作用域字段item,为格式化后的表单配置项,可以用于绑定属性 v-bind="item.props" 以及绑定事件 v-on=item.events,props 内置 modelValue 属性关联字段值、events内置 update:modelValue 事件更新字段值。

如果是分组配置项,还支持 groupSlot 配置分组触发器,带 collpased 作用域插槽字段,用于判断分组折叠状态,配合 handleSwitchCollapsed 方法自定义控制分组折叠状态。
在这里插入图片描述

查看 /demo/form/slots.md

自定义表单按钮

ReForm组件默认展示 提交取消 两个按钮,并提供 btns 插槽用于自定义按钮,需要重新这两个按钮,配合ReForm组件实例方法进行组件状态控制。
在这里插入图片描述

查看 /demo/form/btn-slot.md

ReForm属性

字段说明类型默认值
formRefref函数,获取 ElForm 实例(form: InstanceType\<typeof ElForm\> | null) => void-
items必填,表单配置项集合Array<ReFormItem>[]
modelValue表单数据ReFormModelValue-
cols表单网格布局列数number | ReGridResponsive1
colGap表单网格布局水平间距number16
size表单尺寸“large” | “default” | “small”“default”
disabled表单是否禁用booleanfalse
editable表单是否可编辑booleantrue
scrollToError校验失败是否自动定位第一个校验失败字段booleantrue
autoCollapseInValidate校验失败是否自动展开分组,并定位分组内的第一个校验失败字段booleantrue
ignoreBtnLabel是否忽略表单按钮组标签宽度booleantrue
btnSpan表单按钮组网格大小number | ReGridResponsive1
btnSpanStyle表单按钮组内联样式string-
submitBtnText提交按钮文字内容string“确定”
cancelBtnText取消按钮文字内容string“取消”
submitBtnProps提交按钮自定义属性Partial<ButtonProps>-
cancelBtnProps取消按钮自定义属性Partial<ButtonProps>-
tooltipProps表单默认提示语自定义样式Partial<TooltipProps>-
hideBtns隐藏表单按钮组booleanfalse
emptyText只读情况下空内容展示占位符string“-”
request表单提交远程请求方法(model: Record\<string, any\>) => Promise\<any\>-

ReForm事件

事件名说明格式 |
change表单控件字段值发生变化时触发(field: string, value: any, model: MaybeRef<ReFormModelValue>) => void
update:modelValue表单数据更新后触发(model: MaybeRef<ReFormModelValue>) => void
submit点击提交按钮触发,只有未自定义 btns 插槽时有效(formData: ReFormModelValue) => void
cancel点击取消按钮触发,只有未自定义 btns 插槽时有效() => void
success表单提交成功后触发,只有指定 request 时有效(res: any) => void
error表单提交失败后触发,只有指定 request 时有效(res: any) => void

type ReFormModelValue = Record<string, any>

:::info 小TIP

除了上述事件之外,表单控件的具体事件可以通过表单配置项字段 events 进行绑定。

:::

ReForm插槽

插槽名说明
btns自定义表单按钮组,提交和取消需要自定义
[field]-label每个表单配置项都自带一个标签插槽,默认按 [field]-label 格式提供,可通过 labelSlot 自定义插槽名
[field]-control每个表单配置项都自带一个控件插槽,默认按 [field]-control 格式提供,可通过 slot 自定义插槽名
[field]-group表单分组配置项自带一个分组触发器插槽,默认按 [field]-group 格式提供,可通过 groupSlot 自定义插槽名

ReForm Expose

字段说明类型
submiting表单提交状态boolean
reFormRefElForm组件示例InstanceType<typeof ElForm>
formData表单数据对象ShallowRef<Record<string, any>>
formRules表单校验规则集合ShallowRef<Partial<ReFormRules>>
formItems表单配置对象集合ShallowRef<ReFormItem[]>
formVisible表单字段显示状态集合Ref<Record<string, boolean>>
formCollapsed表单分组项展开/折叠状态集合Ref<Record<string, boolean>>
validate同ElForm,校验整个表单(callback: FormValidateCallback) => void
clearValidate同ElForm,清除表单校验状态() => void
resetFields同ElForm,重置表单字段和校验状态(props?: Arrayable\<string\> | undefined) => void
handleSwitchCollapsed切换分组展开/折叠状态(field: string) => void
autoCollapseByErrors如果表单带有分组配置项,可基于校验失败项自动展开分组并定位到第一个错误项(errors?: Record\<string, any\>) => void

ReFormItem配置项

字段说明类型默认值
type表单项类型,text表示纯文本,comp表示组件控件,group表示分组“text” | “comp” | “group”“comp”
labeltype不为"group"下必填,表单项标签名,type=“group” 无效string-
field必填,表单项绑定字段名,type=“group” 也指定一个唯一值,不会作为表单数据项string-
labelWidth表单项标签名宽度大小,默认取 ReForm 配置的labelWidthnumber-
labelPosition表单项标签名位置,默认取 ReForm 配置的labelPositionstring-
customClass表单项容器自定义样式名string-
controlClass表单控件自定义样式名string-
span表单项网格大小number | ReGridResponsive1
defaultValue表单控件默认值,用于 ReForm 初始化表单any-
tooltip表单控件问好提示语,受 labelSlot 插槽影响string-
tips表单控件下方提示文字内容string-
tipsClass表单控件下方提示文字样式string-
comptype="comp"下必填,表单控件组件名,支持全局注册组件string-
childComp表单控件嵌套子组件名stringel-option | el-radio | el-checkbox
options表单控件需要的数据集,如 el-select、el-radio-group、el-checkbox-groupArray<{[labelKey]: string, [valueKey]: any}>-
labelKeyoptions中数据键名名称string‘label’
valueKeyoptions中数据键值名称string‘value’
modelProp表单控件数据绑定属性名string‘modelValue’
modelEvent表单控件数据绑定事件名string‘update:modelValue’
events表单项自定义绑定事件,不需要带 onRecord<string, Function>-
slot表单控件插槽string[field]-control
labelSlot字段名插槽string[field]-label
visible表单项是否显示或是字段联动展示配置boolean | ReFormItemVisibleRule | ReFormItemVisibleRuleCondition-

以下是仅在 type="group" 下有效:

字段说明类型默认值
children分组表单配置项,只在 type="group" 时有效Array<ReFormItem>-
groupSlot分组触发器的自定义插槽名string[field]-group
defaultCollapsed分组触发器默认展开/收起状态booleanfalse
collapsedText分组触发器默认展开/收起的文本boolean["展开", "收起"]
collapsedTriggerProps分组触发器按钮属性Partial<ButtonProps>-
collapsedTriggerIndex分组触发器是否跟随 labelWidth 缩进,只在 labelPositionleft/right 有效booleanfalse

ReForm Types

export type ReFormModelValue = Record<string, any>;

// 响应式网格配置对象
export interface ReGridResponsive {
  [key: string]: number | undefined; // 自定义尺寸
  xs?: number;
  sm?: number;
  md?: number;
  lg?: number;
  xl?: number;
}

// 字段联动配置对象 - 多个匹配
export interface ReFormItemVisibleRule {
  type: "&" | "|"; // 多个匹配条件逻辑关系
  conditions: ReFormItemVisibleRuleCondition[]; // 多个匹配条件
}

// 字段联动配置对象 - 单个匹配
export interface ReFormItemVisibleRuleCondition {
  field: string; // 关联字段名
  value: any; // 关联字段值 formData[field] 与 value的比较 formData[field].includes(value)
  ignoreCase?: boolean;
  type?: // 关联字段判断方式 =(等于),!(非),.(包含),^(开头),$(结尾),&(全部匹配),|(部分匹配)
  "=" | "!=" | "." | "!." | "^=" | "=$" | "!^=" | "!=$" | "&." | "!&." | "|.";
}

扩展

基于动态表单,扩展了 动态搜索条件表单、抽屉表单、模态框表单

抽屉表单

基于ReForm封装的抽屉表单组件,隐藏内置的按钮组,基于抽屉页脚重新声明按钮组。

整体表单配置与ReForm相同,可以快速上手配置。

通过抽屉表单可以用同样的表单配置直接获得一个抽屉展示的交互方式,省去抽屉实现。可以直接配置远程请求方法request实现自动提交接口。

ReDrawerForm属性
字段说明类型默认值
items必填,表单配置项集合Array<ReFormItem>[]
formData表单数据ReFormModelValue-
formPropsReForm属性配置Partial<ExtendFormProps>-
modelValue是否显示抽屉boolean-
disabled是否禁用表单booleanfalse
resetAfterClosed是否在关闭抽屉后重置表单booleantrue
request表单提交接口请求方法ReFormProps[“request”]-
ReDrawerForm事件
事件名说明格式
open抽屉打开时触发() => void
opened抽屉打开后触发() => void
close抽屉关闭时触发() => void
close抽屉关闭后触发() => void
close-auto-focus输入焦点聚焦在 Drawer 内容时的回调() => void
open-auto-focus输入焦点从 Drawer 内容失焦时的回调() => void
update:modelValue抽屉打开/关闭时触发(visible: boolean) => void
change表单控件字段值发生变化时触发(field: string, value: any, model: MaybeRef\<FormModelValue\>) => void
update:formData表单数据更新后触发(model: MaybeRef\<FormModelValue\>) => void
submit点击确定按钮触发,只有未自定义 footer 插槽时有效(formData: FormModelValue) => void
cancel点击取消按钮触发,只有未自定义 footer 插槽时有效() => void
success表单提交接口请求成功后触发,只有设置 request 属性时有效(res: unknow) => void
error表单提交接口请求失败后触发,只有设置 request 属性时有效(res: unknow) => void

type FormModelValue = Record<string, any>

:::info 小TIP

除了上述事件之外,表单控件的具体事件可以通过表单配置项字段 events 进行绑定。

:::

ReDrawerForm插槽
插槽名说明
headerElDrawer抽屉头部插槽
footerElDrawer抽屉页脚插槽,会覆盖默认的页脚表单按钮,需要自行实现表单提交重置
default-header抽屉主体内容头部,放置在表单之前
default-content抽屉主体内容部分,默认时ReForm,可自定义整个ReForm
default-footer抽屉主体内容页脚,放在表单之后

除了上述插槽,ReForm支持的表单插槽也都支持

ReDrawerForm Expose
字段说明类型
reFormRefElForm组件示例InstanceType<typeof ElForm>
innerFormRefReForm组件示例InstanceType<typeof ReForm>
formData表单数据MaybeRef<Record<string, any>>
resetForm重置表单() => void

模态框表单

与抽屉表单类似,通过模态框的形式展示,省去模态框的实现。基本与抽屉表单实现一致。

源代码

Github

可以通过查看具体实现,如果遇到问题可以留言或者提出issue。

如果觉得对您有帮助的话,可以请小编瑞一下

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iWangsd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值