vue3项目封装form表单

编程入门 行业动态 更新时间:2024-10-08 08:31:49

vue3项目封装form<a href=https://www.elefans.com/category/jswz/34/1771263.html style=表单"/>

vue3项目封装form表单

本文基于Element-plus实现二次封装表单组件。

我们都知道表单组件应该是后台管理系统中用得最多的组件,我们不可能每个业务都写一次表单,然后每一次修改都去各自业务中大幅修改,这样就可能导致代码重复率太高了,工作效率频频降低,所以我们需要封装起来,这样我们就可以复用,大大减少项目体积,方便项目的后期维护,提高前端娃的工作效率。由于我们使用表单都是直接使用UI组件库的组件,所以我们需要做二次封装,那么问题来了,二次封装表单组件我们需要考虑什么?

  • 特性复用:必须继承原有组件的所有特性。
  • 命名规范:二次组件名必须见名知意,我一般都是用FormPanel表单这个名。
  • 接口简单:自定义暴露出来的接口越简单越好。
  • 容易拓展:留有自定义插槽,让用户可以自己选择。
  • 功能完善:具备更完善的功能如:表单验证、动态删减表单,集成第三方的插件(富文本)…
  • 场景通用:具备多个场景使用,比如弹框嵌套表单、页面嵌套表单。

话不多说,直接展示代码,以下代码可以直接使用:

<template><el-form:model="model":inline="inline":label-position="labelPosition":label-width="labelWidth":label-suffix="labelSuffix":hide-required-asterisk="hideRequiredAsterisk":require-asterisk-position="requireAsteriskPosition":show-message="showMessage":inline-message="inlineMessage":status-icon="statusIcon":validate-on-rule-change="validateOnRuleChange":size="size":disabled="disabled":scroll-to-error="scrollToError":scroll-into-view-options="scrollIntoViewOptions"ref="formPanelRef"><el-row v-if="inline"><el-col:span="(item.cols && item.cols != '') ? Number(item.cols) : 24/ Number(cols)"v-for="(item, index) in formConfig":key="index"><!-- input类型 --><el-form-itemv-if="item.type === 'input' && item.type === 'textarea'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-inputtype="textarea":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName]" :placeholder="item.placeholder ? item.placeholder : `请输入`":disabled="item.disabled ? item.disabled : false":maxlength="item.maxlength ? item.maxlength : ''":minlength="item.minlength ? item.minlength : ''":show-word-limit="item.showWordLimit ? item.showWordLimit : false":autosize="item.autosize ? item.autosize : false":rows="item.rows ? item.rows : 1"@change="item.change"><template v-if="item.prefix && item.prefix != ''" #prefix>{{item.prefix}}</template><template v-if="item.suffix && item.suffix != ''" #suffix>{{item.suffix}}</template></el-input></el-form-item><el-form-itemv-else-if="item.type === 'input'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-input:type="item.inputType ? item.inputType : 'text'":clearable="clearable" :style="item.style ? item.style : ''" v-model.trim="model[item.fieldName]" :placeholder="item.placeholder ? item.placeholder : `请输入`":disabled="item.disabled ? item.disabled : false":maxlength="item.maxlength ? item.maxlength : ''":minlength="item.minlength ? item.minlength : ''":show-word-limit="item.showWordLimit ? item.showWordLimit : false":autosize="item.autosize ? item.autosize : false":rows="item.rows ? item.rows : 1"@change="item.change"><template v-if="item.prefix && item.prefix != ''" #prefix>{{item.prefix}}</template><template v-if="item.suffix && item.suffix != ''" #suffix>{{item.suffix}}</template></el-input></el-form-item><!-- 自动补全 --><el-form-item v-if="item.type === 'autocomplete'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-autocomplete:clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请输入`":fetch-suggestions="item.suggestions"@select="item.select"@change="item.change"@keydown="inputKeydown($event, item.DisableInput)"><template v-if="item.prefix && item.prefix != ''" #prefix>{{item.prefix}}</template><template v-if="item.suffix && item.suffix != ''" #suffix>{{item.suffix}}</template></el-autocomplete></el-form-item><!-- 数字类型Input增加输入限制 --><el-form-item v-if="item.type === 'inputNumber'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-inputtype="Number":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请输入`"@change="item.change"@keydown="inputKeydown($event, item.DisableInput)"><template v-if="item.prefix && item.prefix != ''" #prefix>{{item.prefix}}</template><template v-if="item.suffix && item.suffix != ''" #suffix>{{item.suffix}}</template></el-input></el-form-item><!-- 自带加减数字类型Input增加输入限制 --><el-form-item v-if="item.type === 'inputNumberBtn'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-inputtype="Number":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请输入`"@change="inputNumberBtnChange(item.fieldName,item.minNum,item.change);"ref="inputNumberBtnRef"@keydown="inputKeydown($event, item.DisableInput)"><template  #prepend><el-button :disabled="model[item.fieldName] <= 1 || model[item.fieldName] == '' || !model[item.fieldName] || model[item.fieldName] == undefined" style="width: 10px !important; min-width: 10px !important;" @click="inputNumberBtnReduce(item.fieldName,item.change)">-</el-button></template><template #append><el-button style="width: 10px !important; min-width: 10px !important;" @click="inputNumberBtnAdd(item.fieldName, item.change)">+</el-button></template></el-input></el-form-item><!-- 范围输入框,默认为数字类型 --><el-form-item v-if="item.type === 'inputrange'":label="item.label" :required="item.rules ? true : false"><el-col :span="11"><el-form-item :prop="item.fieldName[0]":rules="item.rules ? item.rules : []"><el-input@keydown="inputKeydown($event, item.DisableInput)"type="Number":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName[0]]" :disabled="item.disabled ? item.disabled : false"@change="inputrangeStarChange($event, item.fieldName[0],item.fieldName[1])":placeholder="item.placeholder[0] ? item.placeholder[0] : `请输入`"></el-input></el-form-item></el-col><el-col style="text-align: center;" :span="2">{{item.rangeSeparator}}</el-col><el-col :span="11"><el-form-item :prop="item.fieldName[1]":rules="item.rules ? item.rules : []"><el-input@keydown="inputKeydown($event, item.DisableInput)"type="Number":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName[1]]" :disabled="item.disabled ? item.disabled : false"@change="inputrangeEndChange($event, item.fieldName[0],item.fieldName[1])":placeholder="item.placeholder[1] ? item.placeholder[1] : `请输入`"></el-input></el-form-item></el-col></el-form-item><!-- 下拉框 --><el-form-item v-if="item.type === 'select'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-select:filterable="item.filterable === undefined ? true : item.filterable":style="item.style ? item.style : ''" :clearable="clearable" v-model="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请选择`":multiple="item.multiple ? item.multiple : false":collapse-tags="item.collapseTags || false"collapse-tags-tooltip@change="item.change"><el-optionv-for="(optionItem, optionIndex) in item.optionList":key="optionIndex":label="optionItem.label":disabled="optionItem.disabled":value="optionItem.value === undefined ? optionItem.label : optionItem.value"></el-option></el-select></el-form-item><!-- 日期时间--><el-form-item v-if="item.type === 'date'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-date-pickerv-model="model[item.fieldName]":value-format="item.valueFormat ? item.valueFormat :'yyyy-MM-dd'":format="item.valueFormat ? item.valueFormat :'yyyy-MM-dd'":style="item.style ? item.style : ''" :clearable="clearable":disabled="item.disabled ? item.disabled : false":disabled-date="item.disabledDate ? item.disabledDate : null":type="item.dataType ? item.dataType : 'date'":placeholder="item.placeholder ? item.placeholder : `请选择`":start-placeholder="item.startPlaceholder ? item.startPlaceholder : `请选择`":end-placeholder="item.endPlaceholder ? item.endPlaceholder : `请选择`"@change="item.change"></el-date-picker></el-form-item><!-- switch --><el-form-item v-if="item.type === 'switch'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-switchv-model="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":loading="item.loading ? item.loading : false":active-value="item.activeValue ? item.activeValue : true":inactive-value="item.inactiveValue ? item.inactiveValue : false":style="`--el-switch-on-color: ${item.activeColor}; --el-switch-off-color: ${item.inactiveColor}; --el-switch-border-color: ${item.borderColor}`":placeholder="item.placeholder ? item.placeholder : `请输入`":before-change="item.beforeChange ? item.beforeChange : undefined"@change="item.change"></el-switch></el-form-item><!-- 单选框 --><el-form-item v-if="item.type === 'radio'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-radio-group v-model="model[item.fieldName]":disabled="item.disabled ? item.disabled : false":border="item.border ? item.border : false"@change="item.change"><el-radio v-for="(optionItem, optionIndex) in item.optionList" :label="JSON.stringify(optionItem)" :key="optionIndex">{{optionItem.label}}</el-radio></el-radio-group></el-form-item><!-- 多选框 --><el-form-item v-if="item.type === 'checkbox' && model[item.fieldName]":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-checkbox-group v-model="model[item.fieldName]":disabled="item.disabled ? item.disabled : false":min="item.min ? item.min : undefined":max="item.max ? item.max : undefined":text-color="item.textColor ? item.textColor : '#FFFFFF'":fill="item.fill ? item.fill : '#3171F1'"@change="item.change"><el-checkbox v-for="(optionItem, optionIndex) in item.optionList" :label="optionItem" :key="optionIndex">{{optionItem.label}}</el-checkbox></el-checkbox-group></el-form-item><!-- 地图 --><el-form-item v-if="item.type === 'mapInput' && model[item.fieldName]":label="item.label" :prop="item.fieldName.address":rules="item.rules ? item.rules : []"><BaiduMap:placeholder="item.placeholder":disabled="item.disabled ? item.disabled : false":clearable="clearable"v-model:mapData="model[item.fieldName]"/></el-form-item><!-- 省市区选择 --><el-form-itemv-if="item.type === 'regionInput'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-cascaderv-model.trim="model[item.fieldName]" :clearable="clearable" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请选择`":options="regionList"separator="-":props="{value: 'name',label: 'name',children: 'child'}"@change="item.change"/></el-form-item><!-- 上传组件 --><el-form-itemv-if="item.type === 'upload'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><UploadPanel:uploadType="item.uploadType":maxLength="item.maxLength":maxSize="item.maxSize":disabled="item.disabled":FileList="item.initValue":dir="item.dir":localFiles="item.localFiles":project_id="item.project_id"/></el-form-item><!-- 选择项目人员 --><el-form-itemv-if="item.type === 'selectProjectUser'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><SelectProjectUserv-model:userList="model[item.fieldName]":disabled="item.disabled":placeholder="item.placeholder":dialogTitle="item.dialogTitle":separator="item.separator":bottomCount="item.bottomCount":change="item.change"/></el-form-item><!-- 仅展示 --><el-form-item :label-width="item.labelWidth"v-if="item.type === 'show'":label="item.label" style="margin-bottom:10px"class="l_formPanel_show"><div :style="`line-height: 20px; ${item.style}`" v-if="model[item.fieldName]" v-html="model[item.fieldName].replace(/\n/g,'</br>')"></div></el-form-item></el-col><el-col :span="24/ Number(cols)"><slot name="after"></slot></el-col></el-row><template v-else><el-row v-for="(item, index) in formConfig":key="index"><el-col:span="(item.cols && item.cols != '') ? Number(item.cols) : 24"><!-- input类型 --><el-form-itemv-if="item.type === 'input' && item.inputType === 'textarea'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-inputtype="textarea":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName]" :placeholder="item.placeholder ? item.placeholder : `请输入`":disabled="item.disabled ? item.disabled : false":maxlength="item.maxlength ? item.maxlength : ''":minlength="item.minlength ? item.minlength : ''":show-word-limit="item.showWordLimit ? item.showWordLimit : false":autosize="item.autosize ? item.autosize : false":rows="item.rows ? item.rows : (item.inputType === 'textarea' ? 2 : 1)"@change="item.change"><template v-if="item.prefix && item.prefix != ''" #prefix>{{item.prefix}}</template><template v-if="item.suffix && item.suffix != ''" #suffix>{{item.suffix}}</template></el-input></el-form-item><el-form-itemv-else-if="item.type === 'input'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-input:type="item.inputType ? item.inputType : 'text'":clearable="clearable" :style="item.style ? item.style : ''" v-model.trim="model[item.fieldName]" :placeholder="item.placeholder ? item.placeholder : `请输入`":disabled="item.disabled ? item.disabled : false":maxlength="item.maxlength ? item.maxlength : ''":minlength="item.minlength ? item.minlength : ''":show-word-limit="item.showWordLimit ? item.showWordLimit : false":autosize="item.autosize ? item.autosize : false":rows="item.rows ? item.rows : (item.inputType === 'textarea' ? 2 : 1)"@change="item.change"><template v-if="item.prefix && item.prefix != ''" #prefix>{{item.prefix}}</template><template v-if="item.suffix && item.suffix != ''" #suffix>{{item.suffix}}</template></el-input></el-form-item><!-- 自动补全 --><el-form-item v-if="item.type === 'autocomplete'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-autocomplete:clearable="clearable" :style="item.style ? item.style : ''" v-model.trim="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请输入`":fetch-suggestions="item.suggestions":show-word-limit="item.showWordLimit ? item.showWordLimit : false"@select="item.select"@change="item.change"@keydown="inputKeydown($event, item.DisableInput)"><template v-if="item.prefix && item.prefix != ''" #prefix>{{item.prefix}}</template><template v-if="item.suffix && item.suffix != ''" #suffix>{{item.suffix}}</template></el-autocomplete></el-form-item><!-- 数字类型Input增加输入限制 --><el-form-item v-if="item.type === 'inputNumber'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-inputtype="Number":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请输入`"@change="item.change"@keydown="inputKeydown($event, item.DisableInput)"><template v-if="item.prefix && item.prefix != ''" #prefix>{{item.prefix}}</template><template v-if="item.suffix && item.suffix != ''" #suffix>{{item.suffix}}</template></el-input></el-form-item><!-- 自带加减数字类型Input增加输入限制 --><el-form-item v-if="item.type === 'inputNumberBtn'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-inputtype="Number":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请输入`"@change="inputNumberBtnChange(item.fieldName,item.minNum,item.change);"ref="inputNumberBtnRef"@keydown="inputKeydown($event, item.DisableInput)"><template  #prepend><el-button :disabled="model[item.fieldName] <= 1 || model[item.fieldName] == '' || !model[item.fieldName] || model[item.fieldName] == undefined" style="width: 10px !important; min-width: 10px !important;" @click="inputNumberBtnReduce(item.fieldName,item.change)">-</el-button></template><template #append><el-button style="width: 10px !important; min-width: 10px !important;" @click="inputNumberBtnAdd(item.fieldName, item.change)">+</el-button></template></el-input></el-form-item><!-- 范围输入框,默认为数字类型 --><el-form-item v-if="item.type === 'inputrange'":label="item.label" :required="item.rules ? true : false"><el-col :span="11"><el-form-item :prop="item.fieldName[0]":rules="item.rules ? item.rules : []"><el-input@keydown="inputKeydown($event, item.DisableInput)"type="Number":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName[0]]" :disabled="item.disabled ? item.disabled : false"@change="inputrangeStarChange($event, item.fieldName[0],item.fieldName[1])":placeholder="item.placeholder[0] ? item.placeholder[0] : `请输入`"></el-input></el-form-item></el-col><el-col style="text-align: center;" :span="2">{{item.rangeSeparator}}</el-col><el-col :span="11"><el-form-item :prop="item.fieldName[1]":rules="item.rules ? item.rules : []"><el-input@keydown="inputKeydown($event, item.DisableInput)"type="Number":clearable="clearable" :style="item.style ? item.style : ''" v-model="model[item.fieldName[1]]" :disabled="item.disabled ? item.disabled : false"@change="inputrangeEndChange($event, item.fieldName[0],item.fieldName[1])":placeholder="item.placeholder[1] ? item.placeholder[1] : `请输入`"></el-input></el-form-item></el-col></el-form-item><!-- 下拉框 --><el-form-item v-if="item.type === 'select'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-select :default-first-option="item.defaultFirstOption ? item.defaultFirstOption : false":filterable="item.filterable === undefined ? true : item.filterable":allow-create="item.allowcreate ? item.allowcreate : false":style="item.style ? item.style : ''" :clearable="clearable" v-model="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请选择`":multiple="item.multiple ? item.multiple : false":collapse-tags="item.collapseTags || false"collapse-tags-tooltip@change="item.change"@remove-tag="item.remove"><el-optionv-for="(optionItem, optionIndex) in item.optionList":key="optionIndex":label="optionItem.label":disabled="optionItem.disabled":value="optionItem.value === undefined ? optionItem.label : optionItem.value"></el-option></el-select></el-form-item><!-- 日期时间--><el-form-item v-if="item.type === 'date'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-date-pickerv-model="model[item.fieldName]":value-format="item.valueFormat ? item.valueFormat :'yyyy-MM-dd'":format="item.valueFormat ? item.valueFormat :'yyyy-MM-dd'":style="item.style ? item.style : ''" :clearable="clearable":disabled="item.disabled ? item.disabled : false":disabled-date="item.disabledDate ? item.disabledDate : null":type="item.dataType ? item.dataType : 'date'":placeholder="item.placeholder ? item.placeholder : `请选择`":start-placeholder="item.startPlaceholder ? item.startPlaceholder : `请选择`":end-placeholder="item.endPlaceholder ? item.endPlaceholder : `请选择`"@change="item.change"></el-date-picker></el-form-item><!-- switch --><el-form-item v-if="item.type === 'switch'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-switchv-model="model[item.fieldName]" :disabled="item.disabled ? item.disabled : false":loading="item.loading ? item.loading : false":active-value="item.activeValue ? item.activeValue : true":inactive-value="item.inactiveValue ? item.inactiveValue : false":style="`--el-switch-on-color: ${item.activeColor}; --el-switch-off-color: ${item.inactiveColor}; --el-switch-border-color: ${item.borderColor}`":placeholder="item.placeholder ? item.placeholder : `请输入`":before-change="item.beforeChange ? item.beforeChange : undefined"@change="item.change"></el-switch></el-form-item><!-- 单选框 --><el-form-item v-if="item.type === 'radio'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-radio-group v-model="model[item.fieldName]":disabled="item.disabled ? item.disabled : false":border="item.border ? item.border : false"@change="item.change"><el-radio v-for="(optionItem, optionIndex) in item.optionList" :label="JSON.stringify(optionItem)" :key="optionIndex">{{optionItem.label}}</el-radio></el-radio-group></el-form-item><!-- 多选框 --><el-form-item v-if="item.type === 'checkbox' && model[item.fieldName]":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-checkbox-group v-model="model[item.fieldName]":disabled="item.disabled ? item.disabled : false":min="item.min ? item.min : undefined":max="item.max ? item.max : undefined":text-color="item.textColor ? item.textColor : '#FFFFFF'":fill="item.fill ? item.fill : '#3171F1'"@change="item.change"><el-checkbox v-for="(optionItem, optionIndex) in item.optionList" :label="optionItem" :key="optionIndex">{{optionItem.label}}</el-checkbox></el-checkbox-group></el-form-item><!-- 地图 --><el-form-item v-if="item.type === 'mapInput' && model[item.fieldName]":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><BaiduMap:placeholder="placeholder":disabled="item.disabled ? item.disabled : false":clearable="clearable"v-model:mapData="model[item.fieldName]"/></el-form-item><!-- 省市区选择 --><el-form-itemv-if="item.type === 'regionInput'":label="item.label" :prop="item.fieldName":rules="item.rules ? item.rules : []"><el-cascaderv-model.trim="model[item.fieldName]" :clearable="clearable" :disabled="item.disabled ? item.disabled : false":placeholder="item.placeholder ? item.placeholder : `请选择`":options="regionList"separator="-":props="{value: 'name',label: 'name',children: 'child'}"@change="item.change"/></el-form-item><!-- 仅展示 --><el-form-item :label-width="item.labelWidth"v-if="item.type === 'show'":label="item.label" style="margin-bottom:10px"class="l_formPanel_show"><div :style="`line-height: 20px; ${item.style}`" v-if="model[item.fieldName]" v-html="model[item.fieldName].replace(/\n/g,'</br>')"></div></el-form-item></el-col></el-row></template></el-form>
</template>
<script>
import { reactive,toRefs,onMounted, getCurrentInstance, watch} from 'vue';
import region from '../../assets/json/region';
export default {name: '',props: {formConfig: { // 表单的渲染数据,必须type: Array,default: ()=> {return [];},required: true,},// model: { // 表单数据对象//   type: Object,// 	default: ()=> {// 	return {};// 	}// },// rules: { // 表单验证规则//   type: Object,// 	default: ()=> {// 	return {};// 	}// },cols: { // 每一行显示数量,必须可以被24整除type: [String,Number],default: 2},inline: { // 行内表单模式type: Boolean,default: false},labelPosition: { // 表单域标签的位置, 当设置为 left 或 right 时,则也需要设置 label-width 属性type: String,default: 'right'},labelWidth: { // 标签的长度,例如 '50px'。 作为 Form 直接子元素的 form-item 会继承该值。 可以使用 auto。type: [String,Number],default: '100px'},labelSuffix: { // 表单域标签的后缀type: String,default: ''},hideRequiredAsterisk: { // 是否隐藏必填字段标签旁边的红色星号。type: Boolean,default: false},requireAsteriskPosition: { // 星号的位置。'left' | 'right'type: String,default: 'left'},showMessage: { // 是否显示校验错误信息type: Boolean,default: true},inlineMessage: { // 是否以行内形式展示校验信息type: Boolean,default: false},statusIcon: { // 是否在输入框中显示校验结果反馈图标type: Boolean,default: false},validateOnRuleChange: { // 是否在 rules 属性改变后立即触发一次验证type: Boolean,default: true},size: { // 用于控制该表单内组件的尺寸 '' | 'large' | 'default' | 'small'type: String,default: ''},disabled: { // 是否禁用该表单内的所有组件。 如果设置为 true, 它将覆盖内部组件的 disabled 属性type: Boolean,default: false},scrollToError: { // 当校验失败时,滚动到第一个错误表单项type: Boolean,default: true}, scrollIntoViewOptions: { //当校验有失败结果时,滚动到第一个失败的表单项目 object/ booleantype: [Object, Boolean],default: ''},clearable: { // 是否可清空type: Boolean,default: true},},components: {UploadPanel,SelectProjectUser},setup(props) {const { proxy } = getCurrentInstance(); // 相当于之前的thisconst data = reactive({model: {},regionList: region,});const createFormkey = (type)=> {let formKeyList = {};props.formConfig.map(item => {if(typeof item.fieldName == 'string') {formKeyList[item.fieldName] = item.initValue === undefined ?  '' : item.initValue;} else { // 处理范围输入的keyformKeyList[item.fieldName[0]] = item.initValue[0] ? item.initValue[0] : '';formKeyList[item.fieldName[1]] = item.initValue[1] ? item.initValue[1] : '';}});if(type && type == 'update'){ // 更新组件内容保留历史数据for(let key in data.model){props.formConfig.map(item => {if(item.fieldName == key){formKeyList[key] = data.model[key];}}) }}data.model = formKeyList;};const inputKeydown = (e, DisableInput)=> { // 数字类型输入框禁止输入不合法字符let key = e.key;let DisableInputStr = '';if(DisableInput){DisableInputStr = DisableInput;} else {DisableInputStr = 'e,+,-,Shift'}// console.log(key, '---key')if(DisableInputStr.indexOf(key) > -1) {e.returnValue = false;return false};return true;};/*** @description: 清除表单验证* proxy.$refs.FormPanelRef.clearValidate();* @return {*}* @author: */	const clearValidate = () => {return proxy.$refs.formPanelRef.clearValidate();};/*** @description: 清除指定数据,不穿清除全部* proxy.$refs.FormPanelRef.clearKey(['keyName']);* @return {*}* @author: */	const clearKey = (key) => {if(key&&key.length>0){props.formConfig.map(item => {key.map(keyItem => {if(item.fieldName == keyItem){data.model[keyItem] = item.initValue;}})})} else {createFormkey();}};/*** @description: 清除数据和表单验证* proxy.$refs.FormPanelRef.clear();* @return {*}* @author: */	const clear = () => {clearValidate();clearKey();};/*** @description: 设置数据* proxy.$refs.FormPanelRef.set('key', 'value');* @return {*}* @author: */	const set = (key, value) => {data.model[key] = value;};/*** @description: 得到数据* proxy.$refs.FormPanelRef.get('key');* @return {*}* @author: */	const get = (key) => {return data.model[key];};/*** @description: 验证表单并输入结果通过* proxy.$refs.FormPanelRef.FormPanelValidate().then((res)=> {console.log(res,)})* @return {*}* @author: */		const validate = ()=> { // 验证结果并输出return new Promise((resolve, reject) => {proxy.$refs.formPanelRef.validate((valid) => {if(valid) {let formData = JSON.parse(JSON.stringify(proxy.model))resolve(formData);} else {return false;}})})};const inputrangeStarChange = (e, skey, eKey)=> { // 范围查询输入框初始值if(proxy.model[eKey] && Number(proxy.model[eKey]) <= Number(e)) {if(proxy.model[eKey] > 1) {proxy.model[skey] = Number(proxy.model[eKey])  - 1;} else {proxy.model[skey] = 0;}}};const inputrangeEndChange = (e, skey, eKey)=> { // 范围查询输入框结束if(proxy.model[skey] && Number(proxy.model[skey]) >= Number(e)) {proxy.model[eKey] = Number(proxy.model[skey])  + 1;}};const inputNumberBtnChange = (key, minNum, change)=> {if(minNum && data.model[key] && data.model[key] != '' && data.model[key] != null && data.model[key] != undefined){if(Number(data.model[key]) < Number(minNum)){data.model[key] = Number(minNum)}};change(data.model[key]);}const inputNumberBtnAdd = (key, change)=> { // 数字加if(data.model[key] == '' || !data.model[key] || data.model[key] == null || data.model[key] == undefined){data.model[key] = 1;} else {data.model[key] = Number(data.model[key]) + 1};change(data.model[key]);};const inputNumberBtnReduce = (key,change)=> { // 数字减data.model[key] = Number(data.model[key]) - 1;change(data.model[key]);};onMounted(() => {createFormkey();});watch(props.formConfig,(newVal,oldVal)=>{createFormkey('update');});return {...toRefs(data),inputKeydown,clearValidate,validate,inputrangeStarChange,inputrangeEndChange,inputNumberBtnAdd,inputNumberBtnReduce,inputNumberBtnChange,clearKey,clear,set,get,};}
}
</script>
<style lang='scss' scoped>
:deep(.el-form-item){width: 100%;.el-input{width: 100% !important;}.el-select{width: 100% !important;}.el-cascader{width: 100% !important;}
}
:deep(.el-input__prefix){margin-right: 5px;
}
:deep(.el-input__suffix){margin-left: 5px;
}</style>
<style>
/* // 取消input的上下箭头 */
input::-webkit-outer-spin-button,  
input::-webkit-inner-spin-button{  -webkit-appearance: none !important;  margin: 0;  
}
/* 火狐 */
input[type="number"]{-moz-appearance: textfield;appearance: textfield;
}
</style>

接下来我来告诉大家怎么使用:

#### FormPanel 组件调用`组件参数API`- formConfig{Array | 表单面板组件数据数组,支持动态赋值(数据数组必须是新的引用)}
- inline{Boolean | 是否启用行内表单, 默认值 false}
- cols{Number | 每行显示多小列,默认是 2,注意:只能是被 24 整除的值}
- labelWidth{Number | label 标签的宽度,默认是 120}`formConfig 公用字段配置项`- type{String | 类型,支持 input-输入框 / inputNumber-数字类型输入框 / inputrange-区间输入 / select-下拉框 / date-日期选择 / switch-开关 / radio-单选 / checkbox-多选框 / mapInput-地图 / regionInput-省市区选择 / upload-上传}
- label{String | 标题}
- fieldName{String | 字段名称}
- initValue{All | 初始值}
- placeholder{String | 提示文字}
- rules{Array | 验证提示文字}
- style{Object | 内容样式}
- disabled{Boolean | 是否禁用}
- change{Function | 触发函数}`示例代码````bash
# template
<template><FormPanel :formConfig="formConfig" ref="FormRef":inline="true":cols="4"/>
</template># js
export default {data() {return {formConfig: this.createFormConfig(),};},methods: {createFormConfig() {return [{type: 'input', // 普通输入框inputType: 'text', // 类型, text/textarealabel: '字符串:', // 标签文本cols: '', // 自定义列fieldName: 'stringName', // 字段名称placeholder: '请输入商品名称', // 提示文字initValue: '', // 默认值rules: [{ required: false, message: '请选择所属分类', trigger: 'blur' }],style: {}, // 自定义样式disabled: false, // 是否禁用 booleanmaxlength: '', //最大输入长度 string/numberminlength: '', // 最小输入长度 numbershowWordLimit: false, // 	是否显示统计字数, 只在 type 为 'text' 或 'textarea' 的时候生效 booleanrows: 2, // 输入框行数,仅 inputType 为 'textarea' 时有效 numberautosize: false, // textarea 高度是否自适应,仅 type 为 'textarea' 时生效。 可以接受一个对象,比如: { minRows: 2, maxRows: 6 }change: (val) => {console.log(val, 'val--------')}},{type: 'input', // 普通输入框inputType: 'textarea', // 类型, text/textarealabel: '文本类型', // 标签文本cols: '', // 自定义列fieldName: 'textareaName', // 字段名称placeholder: '请输入商品名称', // 提示文字initValue: '', // 默认值rules: [{ required: false, message: '请选择所属分类', trigger: 'blur' }],style: {}, // 自定义样式disabled: false, // 是否禁用 booleanmaxlength: '', //最大输入长度 string/numberminlength: '', // 最小输入长度 numbershowWordLimit: false, // 	是否显示统计字数, 只在 type 为 'text' 或 'textarea' 的时候生效 booleanrows: 2, // 输入框行数,仅 inputType 为 'textarea' 时有效 numberautosize: { // 默认使用, 优先级高于rowsminRows: 1, maxRows: 2}, // textarea 高度是否自适应,仅 type 为 'textarea' 时生效。 可以接受一个对象,比如: { minRows: 2, maxRows: 6 }change: (val) => {console.log(val, 'val--------')}},{type: 'inputNumber',label: '数字类型 :',fieldName: 'numeberName',placeholder: '请输入上门人数',initValue: '',prefix: '¥', // 插入左侧的内容suffix: '人', // 插入右侧的内容DisableInput: 'e,+,-,Shift,.', // 禁止输入的值,默认值e,+,-,Shiftrules: [{ required: false, message: '请输入上门人数', trigger: 'blur' }],disabled: false, // 是否禁用maxlength: '', //最大输入长度minlength: '', // 最小输入长度showWordLimit: false, // 	是否显示统计字数, 只在 type 为 'text' 或 'textarea' 的时候生效rows: 2, // 输入框行数,仅 inputType 为 'textarea' 时有效autosize: false, // textarea 高度是否自适应,仅 type 为 'textarea' 时生效。 可以接受一个对象,比如: { minRows: 2, maxRows: 6 }style: {},change: (val) => {console.log(val, 'val--------')}},{type: 'inputNumberBtn', // 加减号inputlabel: '持续时长:',fieldName: 'planed_duration',placeholder: '请输入持续时长',initValue: '',DisableInput: 'e,+,-,Shift,.',style: 'width: 220px !important;',disabled: false, // 是否禁用rules: [{ required: true, message: '请选择持续时长', trigger: 'blur' }],},{type: 'inputrange',label: '区间输入',fieldName: ['min_price', 'max_price'],placeholder: ['请输入', '请输入'],initValue: ['', ''],rangeSeparator: '至',rules: [{ required: false, message: '请输入', trigger: 'blur' }],disabled: false, // 是否禁用maxlength: '', //最大输入长度minlength: '', // 最小输入长度showWordLimit: false, // 	是否显示统计字数, 只在 type 为 'text' 或 'textarea' 的时候生效rows: 2, // 输入框行数,仅 inputType 为 'textarea' 时有效autosize: false, // textarea 高度是否自适应,仅 type 为 'textarea' 时生效。 可以接受一个对象,比如: { minRows: 2, maxRows: 6 }},{type: 'select',label: '下拉框:',fieldName: 'selectName',placeholder: '请选中所属分类',initValue: '',optionList: [{ label: '全部', value: '1' }, { label: '待确认', value: '2' }],multiple: false, // 是否多选, 多选时initValue类型是数组collapseTags: true, // 多选时是否合并文字,默认合并allowcreate: true, //是否创建新的条目defaultFirstOption: true, //是否默认第一选项,此字段为true时,按下回车就可以选中当前选项列表中第一个选项style: {width: '200px'},change: (val) => {console.log(val, 'val--------')}},{type: 'date',label: '日期选择:',fieldName: 'dateName',placeholder: '请选择日期',startPlaceholder: '', // 范围选择时开始日期的占位内容endPlaceholder: '', // 范围选择时结束日期的占位内容initValue: '',dataType: 'monthrange', // 	year(年-YYYY)/month(月-YYYY-MM)/date(日-YYYY-MM-DD)/dates(多日期选择)/datetime(日期时间-YYYY-MM-DD hh:mm:ss)/ week(周-ww 周)/datetimerange(日期时间段-YYYY-MM-DD hh:mm:ss)/daterange(日期段-YYYY-MM-DD)/ monthrange(月份范围-YYYY-MM)valueFormat: 'YYYY-MM', // 日期格式默认年月日disabled: false, // 是否禁用change: (val) => {console.log(val, 'val--------')}},{type: 'switch',label: '开关:',fieldName: 'switchName',initValue: '0',placeholder: '',disabled: false, // 是否禁用loading: false, // 是否显示loadingactiveValue: '1', // 打开时的值inactiveValue: '0', // 关闭时的值activeColor: '#3171F1', // 打开时的颜色inactiveColor: '#C0CCDA', // 关闭时的颜色borderColor: '', // 开关边框颜色validateEvent: true, // 切换时是否触发表单校验beforeChange: () => { // switch 状态改变前的钩子, 返回 false 或者返回 Promise 且被 reject 则停止切换return new Promise((resolve, reject) => {setTimeout(() => {return resolve(true)return reject(new Error('Error'))}, 1000)})},change: (val) => { // 	switch 状态发生变化时的回调函数console.log(val, 'val--------')}},{type: 'radio',label: '单选框:',fieldName: 'radioName',initValue: '',disabled: false, // 是否禁用border: false, // 是否显示边框optionList: [{ label: '全部', value: '1' }, { label: '待确认', value: '2' }], // 选项数组,返回值为整个对象change: (val) => {console.log(val, 'val--------')}},{type: 'checkbox',label: '多选框:',fieldName: 'checkboxName',placeholder: '请选择日期',initValue: [],disabled: false, // 是否禁用min: undefined, // 可被勾选的 checkbox 的最小数量max: 999, // 可被勾选的 checkbox 的最大数量textColor: '#FFFFFF', // 当按钮为活跃状态时的字体颜色fill: '#3171F1', // 当按钮为活跃状态时的边框和背景颜色optionList: [{ label: '全部', value: '1' }, { label: '待确认', value: '2' }],change: (val) => {console.log(val, 'val--------')}},{type: 'mapInput',label: '地图',fieldName: 'mapInputName',placeholder: '请选择定位',initValue: {province: '', // 省city: '', // 市area: '', // 区address: '', // 详细地址lng: 0,  // 定位横坐标lat: 0, // 定位纵坐标},disabled: false, // 是否禁用rules: [{ required: true, message: '请选择定位', trigger: 'blur' }],},{type: 'regionInput', // 普通输入框label: '省市区:', // 标签文本cols: '', // 自定义列fieldName: 'regionInputName', // 字段名称placeholder: '请选择', // 提示文字initValue: '', // 默认值rules: [{ required: false, message: '请选择所', trigger: 'blur' }],change: (val) => {console.log(val, 'val--------')}},{type: 'upload', // 普通输入框label: '上传', // 标签文本cols: '', // 自定义列fieldName: 'uploadName', // 字段名称initValue: [], // 默认值uploadType: 'uploadFile',// 组件的类型, 支持 uploadFile(上传图频文件),uploadImg(上传图片)showFile(仅展示)  默认值: uploadFile}maxLength: 10, // 上传数量,默认值10maxSize: 1000, // 默认1000Mdir: '', // 存储文件的目录,后端提供disabled: false,rules: [{ type: 'array', required: true, message: '请上传', trigger: 'change' }],change: (val) => {console.log(val, 'val--------')}},{ // 选择项目人员type: 'selectProjectUser',label: '审批人:', // 标签文本fieldName: 'user_data', // 字段名称placeholder: '请选择', // 提示文字dialogTitle: '选择审批人', // 弹窗名称separator: '>', // 分隔符bottomCount: true, // 启用底部计数initValue: [], // 默认值},{type: 'show',label: '仅展示:',fieldName: 'show',initValue: '展示的内容'},]},}
};

更多推荐

vue3项目封装form表单

本文发布于:2024-02-07 00:09:42,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1751744.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:表单   项目   form

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!