目录

一、实现背景

二、简介

三、组织架构设计 

四、实现方式

五、代码示例

六、示例代码效果预览

七、项目预览地址 & 项目源码地址

目前项目还有诸多待完善的地方,大家有好的想法、建议、意见等欢迎再次评论,或于github提交Issues


一、实现背景

        一切为了摸鱼而努力!!!

        在现代Web应用程序中,表单组件是不可或缺的一部分。但是,手动创建每个表单项是一个非常繁琐的过程。为此,我提供了一个基于Vue3的可配置的表单组件,帮助您快速构建表单,无需手动编写HTML或JavaScript代码。这篇文章将向您展示如何使用JSON配置文件一站式生成Vue3 Form表单组件,并在项目中使用它。

二、简介

        此表单组件是目前内嵌在一个基础项目中的,并没有作单独的npm包进行发布,因为目前是一个比较简单且基础的版本,需要优化的点还非常多。希望大家能多多提出宝贵的意见或建议,本文主要是针对实现思路等进行描述。

        目前实现功能:栅格化布局、监听单个表单数据变化、Form 表单除upload外的所有子组件。

        通过JSON配置一站式生成form表单,该组件保留了ElementPlus全部的使用习惯和使用方式,对ElementPlus原功能进行了完美的保留,支持所有属性设置(方法使用统一事件监听替代)

三、组织架构设计 

        在当前的表单组件中,数据层、UI层、事件层等模块相互独立,通过交互来协调和通信。

        其中,数据层负责存储和管理表单组件的数据;UI层负责渲染表单组件的外观;事件层负责处理用户与表单组件互动时的事件。通过这种方式,我们实现了一个高度可扩展和可重用的表单组件。

四、实现方式

        Vue3支持使用JSX/TSX语法,通过JSX/TSX(我这里使用的是TSX)进行不同表单组件的生成,枚举出Form表单的所有子组件。这里采用TSX的方式可以避免每一种组件都要去写一份Vue文件;

        通过匹配组件类型,生成对应的每一个表单组件;

        为保留ElementPlus组件所有属性,需要采用透传的方式,去列出每一个组件所可能用到的属性显然是不明智的;

        布局排版的生成采用el-row、el-col实现栅格布局,可通过配置进行动态调整;

        ElementPlus表单组件中的所有方法显然不是那么好处理的,因此使用同一个方法去监听每个表单项的变化,并提供给“用户”此时变化的key、newVal以及oldVal,这里采用Proxy进行了数据拦截;

        提供一个表单校验和重置表单数据的方法。

        某些ElementPlus表单组件中会提供一些插槽给用户使用,因此这些插槽也需要保留下来

组件生成示例:

case 'el-input':
    return (
        <ElInput
            type={elItem.specificType}
            {...elItem.bindObj}
            v-model={formData[elItem.key]}
            v-slots={itemInteriorSlotsObject}
        />
    )

五、代码示例

  • 配置项数据
const FormConfig = reactive({
    rowConfigBind: {
        gutter: 20,
        colSpan: 8
        // className: 'row-class'
    },
    formConfigBind: {
        labelPosition: 'top'
    },
    colsList: [
        {
            label: '一个普通的输入框',
            colSpan: 8,
            type: 'el-input',
            specificType: 'text',
            bindObj: {
                placeholder: '请输入文字',
                formatter: (value: any) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ','),
                parser: (value: any) => value.replace(/\$\s?|(,*)/g, '')
            },
            key: 'name'
        },
        {
            label: '一个普通的输入框',
            htmlLabel:
                '<span class="customize-label-style">\n' +
                '            自定义tooltip效果\n' +
                '                <span class="tip-content-wrap">\n' +
                '                      <span class="tip-content">这是自己定义的tooltip</span>\n' +
                '                      <span class="triangle-style"></span>\n' +
                '                </span>\n' +
                '\n' +
                '        </span>\n',
            colSpan: 8,
            type: 'el-input',
            specificType: 'text',
            bindObj: {
                placeholder: '请输入文字',
                formatter: (value: any) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ','),
                parser: (value: any) => value.replace(/\$\s?|(,*)/g, '')
            },
            key: 'name2'
        },
        {
            label: '添加了append文字的输入框',
            colSpan: 8,
            type: 'el-input',
            bindObj: {
                placeholder: '请输入'
            },
            rules: [
                {
                    required: true,
                    message: '请输入',
                    trigger: 'change'
                }
            ],
            slots: [
                {
                    name: 'append',
                    content: '.com'
                }
            ],
            key: 'comAdress'
        },
        {
            label: '添加了append JSX组件的输入框',
            colSpan: 8,
            type: 'el-input',
            bindObj: {
                placeholder: '请输入'
            },
            slots: [
                {
                    name: 'append',
                    content: TestTSXComp
                }
            ],
            key: 'appendJSXComp'
        },
        {
            label: '添加了append Vue组件的输入框',
            colSpan: 8,
            type: 'el-input',
            bindObj: {
                placeholder: '请输入'
            },
            slots: [
                {
                    name: 'append',
                    content: TestVueComp
                }
            ],
            key: 'appendVueComp'
        },
        {
            label: '数字输入框',
            colSpan: 4,
            type: 'el-input-number',
            bindObj: {
                placeholder: '请输入'
            },
            key: 'inputNumberVal'
        },
        {
            label: '测试表单生成函数',
            type: 'slots',
            key: 'content',
            colSpan: 24
        },
        {
            label: '下拉选',
            colSpan: 8,
            type: 'el-select',
            bindObj: {
                placeholder: '请选择',
                multiple: true
            },
            options: [
                {
                    label: '第一个选项',
                    value: 'A',
                    bindObj: {
                        disabled: true
                    }
                },
                {
                    label: '第二个选项',
                    value: 'B'
                },
                {
                    label: '第三个选项',
                    value: 'C'
                }
            ],
            key: 'optionValue'
        },
        {
            label: '单选框',
            colSpan: 8,
            type: 'el-radio',
            options: [
                {
                    label: '第一个选项',
                    value: 'A',
                    bindObj: {
                        disabled: true
                    }
                },
                {
                    label: '第二个选项',
                    value: 'B'
                },
                {
                    label: '第三个选项',
                    value: 'C'
                }
            ],
            key: 'radioValue'
        },
        {
            label: '按钮单选框',
            colSpan: 8,
            type: 'el-radio',
            bindObj: {
                textColor: 'red'
            },
            options: [
                {
                    label: '第一个选项',
                    value: 'A',
                    isButton: true
                },
                {
                    label: '第二个选项',
                    value: 'B',
                    isButton: true
                },
                {
                    label: '第三个选项',
                    value: 'C',
                    isButton: true // 如果是button样式展示,那么设置此属性为true
                }
            ],
            key: 'radioBtnValue'
        },
        {
            label: '自动补全输入框',
            colSpan: 8,
            type: 'el-autocomplete',
            bindObj: {},
            querySearchFun: querySearchFun,
            key: 'autocompleteValue'
        },
        {
            label: '日期选择框',
            colSpan: 8,
            type: 'el-date-picker',
            specificType: 'date',
            bindObj: {},
            key: 'detePickerValue'
        },
        {
            label: '日期时间选择框',
            colSpan: 8,
            type: 'el-date-picker',
            specificType: 'datetime',
            bindObj: {},
            key: 'deteTimePickerValue'
        },
        {
            label: '评分',
            colSpan: 8,
            type: 'el-rate',
            bindObj: {
                voidIcon: 'ChatRound',
                colors: ['#409eff', '#67c23a', '#FF9900'],
                icons: [ChatRound, ChatLineRound, ChatDotRound]
            },
            key: 'rateValue'
        },
        {
            label: '滑块',
            colSpan: 8,
            type: 'el-slider',
            bindObj: {
                showInput: true
            },
            key: 'elSliderValue'
        },
        {
            label: '开关',
            colSpan: 8,
            type: 'el-switch',
            bindObj: {
                style: '--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949'
            },
            key: 'elSwitchValue'
        },
        {
            label: '时间选择器',
            colSpan: 4,
            type: 'el-time-picker',
            key: 'timePickerValue'
        },
        {
            label: '时间选择',
            colSpan: 4,
            type: 'el-time-select',
            key: 'timeSelectValue'
        }
    ]
})
  • 表单数据
// 数据定义
const formData = reactive({
    name: '',
    comAdress: '',
    inputNumberVal: '',
    appendJSXComp: '',
    appendVueComp: '',
    optionValue: [],
    autocompleteValue: ''
})
  • 组件应用
<GenerateElForm
    ref="formInstance"
    :form-config="FormConfig"
    :form-data="formData"
    @updateFormValue="watcherFun"
>
    <template #content>
        <div class="form-slot-one">这是插槽的内容</div>
    </template>
</GenerateElForm>
  •  watcherFun
// 监听数据变化的方法
const watcherFun = (key: string, oldVal: any, newVal: any) => {
    console.log(
        '监听到数据变化',
        `当前变化的key是: ${key}, 它的旧值是: ${oldVal}, 它的新值是: ${newVal}`
    )
}

六、示例代码效果预览

七、项目预览地址 & 项目源码地址

项目预览地址:http://1.14.75.249/

项目源码地址:https://github.com/zuotiandeni/lcyBlog

目前项目还有诸多待完善的地方,大家有好的想法、建议、意见等欢迎再次评论,或于github提交Issues

Logo

前往低代码交流专区

更多推荐