小程序开发定制vue3 ts element plus form表单二次封装详细步骤 (附参数、类型详细介绍及简单使用示例)

前言

上篇 小程序开发定制讲到项目中经常会用到 table 表格,小程序开发定制所以做了封装。当然,form 小程序开发定制表单使用的频率依然很高,小程序开发定制所以和封装 table 小程序开发定制表格的思路相似,对 form 小程序开发定制表单也做了一个二次封装的组件。

效果图



1. EasyForm 表单

src/components/EasyForm/index.vue Form 小程序开发定制表单组件封装

<template>    <el-form @submit.prevent :model="model" v-bind="_options" ref="formRef">        <template v-for="(item, index) in fieldList" :key="index">             <!-- 单选框 -->            <el-form-item :label="item.label" v-if="item.type === 'radio'" :rules="item.rules" :prop="[item.field]">                <el-radio-group v-model="model[item.field]" :disabled="item.disabled">                    <el-radio                        :label="val[item.options?.valueKey || 'value']"                        size="large"                        v-for="val in item.options?.data"                        :key="val[item.options?.valueKey || 'value']">                        {{ val[item.options?.labelkey || 'label'] }}                    </el-radio>                </el-radio-group>            </el-form-item>            <!-- 复选框 -->            <el-form-item                :label="item.label"                v-else-if="item.type === 'checkbox'"                :rules="item.rules"                :prop="[item.field]">                <el-checkbox-group v-model="model[item.field]" :disabled="item.disabled">                    <el-checkbox                        v-for="c in item.options?.data"                        :key="c[item.options?.valueKey || 'value']"                        :label="c[item.options?.valueKey || 'value']"                        >{{ c[item.options?.labelkey || 'label'] }}</el-checkbox                    >                </el-checkbox-group>            </el-form-item>            <!-- 下拉框 -->            <el-form-item                :label="item.label"                v-else-if="item.type === 'select'"                :rules="item.rules"                :prop="[item.field]">                <!-- <EasySelect                    v-model="model[item.field]"                    clearable                    :disabled="item.disabled"                    :label-key="item.options?.labelkey"                    :value-key="item.options?.valueKey"                    :select-data="item.options?.data" /> -->                <el-select v-model="model[item.field]" :placeholder="item.options?.placeholder || '请选择'" :clearable="item.clearable">                    <el-option                        v-for="s in item.options?.data"                        :key="s[item.options?.valueKey || 'value']"                        :label="s[item.options?.labelkey || 'label']"                        :value="s[item.options?.valueKey || 'value']" />                </el-select>            </el-form-item>            <!-- 小程序开发定制默认输入框 -->            <el-form-item :label="item.label" :rules="item.rules" :prop="[item.field]" v-else>                <el-input                    v-model="model[item.field]"                    :readonly="item.readonly"                    :type="item.type ?? 'text'"                    :placeholder="item.placeholder || item.label"                    :disabled="item.disabled"                     :showPassword="item.showPassword"                    :clearable="item.clearable"                    @keyup.enter="handleKeyUp(item.enterable)"/>            </el-form-item>        </template>        <el-form-item>            <slot name="buttons" :model="model" :formRef="formRef">                <el-button type="primary" @click="onSubmit(formRef)">{{ _options.submitButtonText }}</el-button>                <el-button v-if="_options.showResetButton" type="info" @click="resetForm(formRef)">                    {{ _options.resetButtonText }}                </el-button>                <el-button v-if="_options.showCancelButton" @click="emit('cancel')">                    {{ _options.cancelButtonText }}                </el-button>            </slot>        </el-form-item>    </el-form></template><script lang="ts" setup>    import type { FormInstance } from 'element-plus'    import { ComputedRef, ref, computed } from 'vue'    // 小程序开发定制父组件传递的值    interface Props {        fieldList: Form.FieldItem[]        model?: Record<string, any>        options?: Form.Options    }    // 小程序开发定制表单的数据    const model = ref<Record<string, any>>({})    const formRef = ref<FormInstance>()    const props = defineProps<Props>()    // 设置option默认值,小程序开发定制如果传入自定义的配置则合并option配置项    const _options: ComputedRef<Form.Options> = computed(() => {        const option = {            labelPosition: 'right',            disabled: false,            submitButtonText: '提交',            resetButtonText: '重置',            cancelButtonText: '取消'        }        return Object.assign(option, props?.options)    })    interface EmitEvent {        (e: 'submit', params: any): void        (e: 'reset'): void        (e: 'cancel'): void    }    const emit = defineEmits<EmitEvent>()    defineExpose({        formRef    })    // const model = ref<Record<string, any>>({})    // 根据fieldList初始化model, 如果model有传值就用传递的model数据模型,否则就给上面声明的model设置相应的(key,value) [item.field], item.value是表单的默认值(选填)    props.fieldList.map((item: Form.FieldItem) => {        // 如果类型为checkbox,默认值需要设置一个空数组        const value = item.type === 'checkbox' ? [] : ''        props.model ? (model.value = props.model) : (model.value[item.field] = item.value || value)    })    // 提交按钮    const onSubmit = (formEl: FormInstance | undefined) => {        if (!formEl) return        formEl.validate((valid) => {            if (valid) {                emit('submit', model.value)            } else {                return false            }        })    }    // 输入框回车事件	const handleKeyUp = (enterable: boolean | undefined) => {	    if (!enterable) return	    onSubmit(formRef.value)	}	// 重置    const resetForm = (formEl: FormInstance | undefined) => {        if (!formEl) return        formEl.resetFields()    }</script><style lang="scss" scoped></style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141

复制完Form组件的代码后,会报红线,Form.XXXXX 找不到,这个是全局类型声明。 声明文件已在下方贴出来,直接复制进项目中, 红色警告自然消失。

2. 基本表单使用

src/views/form/index.vue

<template>    <el-card class="mb-5">        <template #header> 基本表单 </template>        <easy-form :fieldList="fieldList" :model="model" @submit="handleBaseSubmit">            <!-- 如果不使用默认的按钮可以使用插槽自定义内容, 插槽返回的model就是当前表单的数据 -->            <!-- <template #buttons="{ model }">                    <el-button">提交</el-button>                </template> -->        </easy-form>    </el-card></template><script lang="ts" setup>    import { exampleForm } from '@/config/form' 	// import { ref } from 'vue'	// import EasyForm from '@/components/EasyForm/index.vue'	// 本项目EasyForm组件自动引入,如复制此代码,需根据路径引入Form组件后使用    const fieldList: Form.FieldItem[] = exampleForm.base    const model = ref<Record<string, any>>({        name: '张三',        gender: 1,        hobbies: [1],        job: 3,        readonly: '只读输入框',        summary: '尤雨溪懂个锤子vue是什么梗'    })    /**     * 注意: model数据模型非必填项,如果仅仅是用于数据收集,model参数可以不用填,表单的submit事件会返回所有搜集的数据对象     *       如果是编辑的情况下,页面需要回显数据,则model数据模型必须要填写     */    const handleBaseSubmit = (model: Record<string, any>) => {        console.log(model)    }</script><style lang="scss" scoped></style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

3. 自定义 key

src/views/form/index.vue

<template>    <el-card class="mb-5">        <template #header> 自定义key </template>        <easy-form :fieldList="customKeyFieldList" :model="model2" />    </el-card></template><script lang="ts" setup>    import { exampleForm } from '@/config/form'    // import { ref } from 'vue'	// import EasyForm from '@/components/EasyForm/index.vue'	// 本项目EasyForm组件自动引入,如复制此代码,需根据路径引入Form组件后使用    const customKeyFieldList: Form.FieldItem[] = exampleForm.customkeyForm    const model2 = ref<Record<string, any>>({        name: '自定义key',        gender: 1    })    /**     * 注意: 如果使用到checkbox,radio,或者select等组件,需要传入组件额外需要的数据,本组件默认设定的读取数据的字段是 label, value     *       可参考下方声明文件 FiledItem options的参数类型描述     *       比如,当前传入的data数据字段名和label、value不匹配,可使用预留的参数 labelkey, valueKey指定字段名     *         customkeyForm: [                    { label: '标题', field: 'name' },                    { label: '性别', field: 'gender', type: 'radio', options: { labelkey: 'title', valueKey: 'val', data: [{ title: '男', val: 1 }, { title: '女', val: 0 }] } },                ],     */    const handleBaseSubmit = (model: Record<string, any>) => {        console.log(model)    }</script><style lang="scss" scoped></style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

4. 自定义表单验证

src/views/form/index.vue

<template>    <el-card class="mb-5">        <template #header> 自定义验证的表单 (使用slot自定义按钮) </template>        <easy-form :fieldList="ruleFieldList">            <!-- 如果不使用默认的按钮可以使用插槽自定义内容, 插槽返回的model就是当前表单的数据, formRef是当前表单的FormInstance -->            <template #buttons="{ model, formRef }">                <el-button @click="handleSubmit(model, formRef)">保存</el-button>            </template>        </easy-form>    </el-card></template><script lang="ts" setup>    import type { FormInstance } from 'element-plus'    import { exampleForm } from '@/config/form' 	// import EasyForm from '@/components/EasyForm/index.vue'	// 本项目EasyForm组件自动引入,如复制此代码,需根据路径引入Form组件后使用    const ruleFieldList: Form.FieldItem[] = exampleForm.ruleForm    /**     *  如果用到了表单验证,又使用slot自定义按钮的话,需要自行实现验证逻辑     *  组件内部已经集成验证,及重置逻辑。表单验证建议使用内置的提交按钮。当通过验证规则,内置提交按钮才会出发submit事件     */    // 下方是使用slot自定义按钮,需要自己实现验证逻辑    const handleSubmit = (model: any, formEl: FormInstance | undefined) => {        if (!formEl) return        formEl.validate((valid) => {            if (valid) {                console.log('submit!', model)            } else {                console.log('error submit!')                return false            }        })    }</script><style lang="scss" scoped></style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

src/config/form.ts 表单配置项, 参数请参考下面参数介绍

// 自定义验证邮箱方法const checkEmail = (rule: any, value: any, callback: any) => {    if (!value) callback(new Error('Please input the email'))    const regExp = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.(com|cn|net)$/    regExp.test(value) ? callback() : callback(new Error('Please input the correct email address'))}// // 自定义验证表单配置数据// export const validationFormFieldList = [//     { label: '姓名', field: 'name', rules: [{ required: true, message: 'name is required' }] },//     { label: '邮箱', field: 'email', rules: [{ required: true, validator: checkEmail }] },// ] as Form.FieldItem[]// 表单配置示例export const exampleForm = {    base: [        { label: '姓名', field: 'name', disabled: true },        { label: '性别', field: 'gender', type: 'radio', options: { data: [{ label: '男', value: 1 }, { label: '女', value: 0 }] } },        { label: '爱好', field: 'hobbies', type: 'checkbox', options: { data: [{ label: '吃饭', value: 1 }, { label: '睡觉', value: 2 }, { label: '写代码', value: 3 }] } },        { label: '工作', field: 'job', type: 'select', options: { data: [{ label: '吃饭', value: 1 }, { label: '睡觉', value: 2 }, { label: '写代码', value: 3 }] } },        { label: '密码', field: 'password', type: 'password', placeholder: '这是一个密码输入框' },        { label: '只读', field: 'readonly', readonly: true, placeholder: '这是一个只读输入框' },        { label: '留言板', field: 'summary', type: 'textarea', placeholder: '留言板' },    ],    customkeyForm: [        { label: '标题', field: 'name' },        { label: '性别', field: 'gender', type: 'radio', options: { labelkey: 'title', valueKey: 'val', data: [{ title: '男', val: 1 }, { title: '女', val: 0 }] } },    ],    ruleForm: [        { label: '姓名', field: 'name', rules: [{ required: true, message: 'name is required' }] },        { label: '邮箱', field: 'email', rules: [{ required: true, validator: checkEmail }] },    ]} as Record<string, Form.FieldItem[]>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

src/types/form/index.d.ts 参数类型声明(声明为全局的类型,方便使用)

declare namespace Form {     type ItemType = 'password' | 'text'|'textarea' | 'radio' | 'checkbox' | 'select'    // 当FiledItem的type === 'radio' | 'checkbox'时,options的参数类型    interface IFieldOptions {        labelkey?: string,        valueKey?: string,        placeholder?: string,        data: Recode<string, any>[]    }    interface Options {        labelWidth?: string | number,        labelPosition?: 'left' | 'right' | 'top',        disabled?: boolean,        size?: 'large' | 'small' | 'default',        showResetButton?: boolean, // 是否展示重置按钮        showCancelButton?: boolean, // 是否展示取消按钮        submitButtonText?: string,        resetButtonText?: string,        cancelButtonText?: string    }    interface FieldItem {        label?: string,        labelWidth?: string | number, // 标签宽度,例如 '50px'。 可以使用 auto。        field: string,        type?: ItemType,        value?: any,        placeholder?: string,        disabled?: boolean,        readonly?: boolean,        options?: IFieldOptions,        rules?: import('element-plus').FormItemRule[]        clearable?: boolean // 是否可清空        showPassword?: boolean, // 是否显示切换密码图标        enterable?: boolean, // 当为输入框时,是否启用回车触发提交功能    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

参数介绍

Form 属性

参数说明类型是否必填默认值
model表单数据对象Record<string, any>
options自定义配置object
fieldListformItem 配置数组Array<object>

Options 配置项

参数说明类型是否必填默认值
labelWidth标签的长度,例如 ‘50px’。 作为 Form 直接子元素的 form-item 会继承该值。 可以使用 auto。string / number
labelPosition表单域标签的位置, 当设置为 left 或 right 时,则也需要设置 label-width 属性‘left’ / ‘right’ / ‘top’‘right’
size用于控制该表单内组件的尺寸large / default /small
disabled是否禁用该表单内的所有组件。 如果设置为 true, 它将覆盖内部组件的 disabled 属性。booleanfalse
submitButtonText提交按钮默认显示的文本内容string‘提交’
resetButtonText重置按钮默认显示的文本内容string‘重置’
cancelButtonText取消按钮默认显示的文本内容string‘取消’
showResetButton是否显示重置按钮boolean
showCancelButton是否显示取消按钮boolean

fieldItem 配置项

参数说明类型是否必填默认值
fieldmodel 的键名string
label标签文本string
type当前 fieldItem 的类型‘password’ / ‘text’ / ‘textarea’ / ‘radio’ / ‘checkbox’ / ‘select’‘text’
value默认显示的值any
placeholder输入框占位文本string
disabled是否禁用booleanfalse
options如果 type=‘checkbox’ / ‘radio’ / 'select’时,需传入此配置项。格式参考 fieldItem options 配置项object-
rules表单验证规则。格式参考 或者参数类型声明Array<RuleItem>-
clearable是否可清空booleanfalse
showPassword是否显示切换密码图标booleanfalse
enterable当为输入框时,是否启用回车触发提交功能booleanfalse

fieldItem options 配置项

参数说明类型是否必填默认值
labelkeylabel 自定义字段名string‘label’
valuevalue 自定义字段名string‘value’
placeholder当 fieldItem type= 'select’时,选择框的提示语string-
datatype=‘checkbox’ / ‘radio’ / 'select’时, 需要的数据Array<object>-

Form 插槽

插槽名说明插槽作用域
buttons自定义按钮区域的内容{ model, formRef }

Form 事件

事件名说明回调参数
submit点击默认的提交按钮触发model
cancel点击取消按钮触发-
reset重置该表单项,将其值重置为初始值,并移除校验结果-

其他

此文档只提供基本的封装思路,如需使用到更多的业务场景,可自行扩展。
FiledItem type 类型可增加 富文本编辑器、 markdown 编辑器, 上传图片等类型,然后根据类型判断把封装好的、放入表单内。

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发