elememt form表单二次封装,elform封装,很全很详细

elememt form表单二次封装,elform封装,很全很详细

更新于:2021-07-29 15:30

功能:input,select,搜索select,textarea,各种年月日,时分秒,switch,单选,多选,文件上传,按钮,text查看只读,富文本编辑器,百度地图(可选)

详解:element的form表单二次封装也很简单,写一个form表单你会发现不一样的地方只是form-item里面的组件类型而已。所以把form-item里面的内容可变化就行了。父级也只需通过一个数组(form-item里面组件类型数组),一个对象(form表单数据对象)控制就行了!为什么要多一个对象,是为了方便数据提交,以及数据验证。这次封装多加了el-col,也没有直接放进弹出框,是为了更加灵活可变!

1、form表单子组件代码(富文本编辑器,可根据项目需求,不引入也行)引入了自己单独二次封装一下

<template> <el-form :model="formData" class="demo-ruleForm" ref="ruleForm" label-position="left" label-width="120px"> <el-col v-for=" (formobj,index) in formObj" v-show="!formobj.notShow" :key="index" :span="formobj.width ? formobj.width : 24"> <el-form-item :label="formobj.label" :prop="formobj.prop" :rules="formobj.rules"> <!-- inupt输入框 --> <el-input v-if="formobj.input" v-model="formData[formobj.prop]" size="small" :disabled="formobj.disabled" :placeholder="formobj.placeholder" @input="inputINPUT($event,index,formobj.prop)" @change="inputChange($event,index,formobj.prop)" /> <!-- textarea输入框 --> <el-input v-if="formobj.textarea" v-model="formData[formobj.prop]" size="small" type="textarea" :rows="formObj.rows" :disabled="formobj.disabled" :placeholder="formobj.placeholder" /> <!-- select选择器 --> <el-select v-if="formobj.select" v-model="formData[formobj.prop]" size="small" :disabled="formobj.disabled" :placeholder="formobj.placeholder" @change="selectChange($event,index,formobj.prop)"> <el-option v-for="(options, sIndex) in formobj.options" :key="sIndex" :label="options.label" :value="options.value" /> </el-select> <!-- select搜索框 --> <el-select v-if="formobj.searchSelect" v-model="formData[formobj.prop]" size="small" :disabled="formobj.disabled" filterable remote reserve-keyword :placeholder="formobj.placeholder" :remote-method="(query)=>remoteMethod(query,index,formobj.prop)" :loading="searchSelectLoading" @change="selectChange($event,index,formobj.prop)"> <el-option v-for="(item,ssIndex) in formobj.options" :key="ssIndex" :label="item.label" :value="item.value" /> </el-select> <!-- 年月日时分秒选择器 --> <el-date-picker v-if="formobj.dateTime" v-model="formData[formobj.prop]" value-format="yyyy-MM-dd HH:mm:ss" type="datetime" size="small" :disabled="formobj.disabled" :placeholder="formobj.placeholder" /> <!-- 年月日时分秒,开始和结束时间 --> <el-date-picker v-if="formobj.dateTimeRange" v-model="formData[formobj.prop]" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd HH:mm:ss" size="small" type="datetimerange" :disabled="formobj.disabled" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" /> <!-- 时分秒选择器 --> <el-time-picker v-if="formobj.timePicker" v-model="formData[formobj.prop]" value-format="HH:mm:ss" format="HH:mm:ss" size="small" :disabled="formobj.disabled" :placeholder="formobj.placeholder" :picker-options="formobj.options" /> <!-- 时分秒选择器,开始和结束时间 --> <el-time-picker v-if="formobj.timePickerIsRange" v-model="formData[formobj.prop]" value-format="HH:mm:ss" format="HH:mm:ss" is-range size="small" :disabled="formobj.disabled" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" placeholder="选择时间范围" /> <!-- 年月日选择器 --> <el-date-picker v-if="formobj.datePicker" v-model="formData[formobj.prop]" value-format="yyyy-MM-dd" size="small" :disabled="formobj.disabled" :placeholder="formobj.placeholder" /> <!-- 年月日选择器,开始和介绍年月日 --> <el-date-picker v-if="formobj.datePickerIsRange" v-model="formData[formobj.prop]" value-format="yyyy-MM-dd" type="daterange" size="small" :disabled="formobj.disabled" :placeholder="formobj.placeholder" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" /> <!-- switch开关 --> <el-switch v-if="formobj.switch" v-model="formData[formobj.prop]" size="small" :disabled="formobj.disabled" @change="formSwitchChange($event,index,formobj.prop)" /> <!-- radio单选框 --> <el-radio-group v-if="formobj.radio" v-model="formData[formobj.prop]" :disabled="formobj.disabled"> <el-radio v-for="(options, rIndex) in formobj.options" :key="rIndex" :label="options.label" :value="options.value" /> </el-radio-group> <!-- checkbox复选框 --> <el-checkbox-group v-if="formobj.checkbox" v-model="formData[formobj.prop]" :disabled="formobj.disabled"> <el-checkbox v-for="options in formobj.options" :key="options.value" :label="options.label" /> </el-checkbox-group> <!-- 文件上传 --> <!-- 如果对象有值就回显,没有值就为空 --> <el-upload v-if="formobj.upload" :ref="formobj.prop" :accept="formobj.accept ? formobj.accept : 'PNG,JPEG'" :file-list=" formData[formobj.prop] ? formData[formobj.prop] : []" :action="`${uploadUrl}${formobj.uploadObj.fileType ? formobj.uploadObj.fileType : '' }`" :limit="formobj.uploadObj.limit" :class="{'hide':formobj.uploadObj.hideUpload || formData[formobj.prop].length==formobj.uploadObj.limit}" :on-preview="handlePictureCardPreview" :on-remove="(file,fileList)=>handleRemove(file,fileList,formobj.uploadObj.limit,formobj.prop,index)" :on-success="(response,file,fileList)=>uploadSuccess(response,file,fileList,formobj.uploadObj.limit,formobj.prop,index)" list-type="picture-card" :auto-upload="true"> <i slot="default" class="el-icon-plus" /> </el-upload> <el-dialog v-if="formobj.upload" :visible.sync="dialogVisible" :append-to-body="true" width="40%"> <img width="100%" :src="dialogImageUrl" alt=""> </el-dialog> <!-- 按钮 --> <el-button v-if="formobj.button" size="small" :disabled="formobj.disabled" :loading="formobj.loading" :type="formobj.buttonType || 'primary'" @click="buttonClick(formobj.prop,index)"> {{ formobj.placeholder }} </el-button> <!-- text展示 --> <span v-if="formobj.text" v-text="formData[formobj.prop]" /> <!-- 计量单位 --> <span v-if="formobj.unit" class="left10">{{ formobj.unit }}</span> <!-- 高德地图 --> <!-- <div class="amap_div" v-if="formobj.aMap"> <el-input size="small" v-model="formData[formobj.prop]" @input="aMapInput($event,formobj.prop)"></el-input> <ul v-show="searchShow==formobj.prop" class="sreach_ul"> <li @click="selectVal(sval,formobj.prop,index)" v-for=" (sval, index) in setSearchVal" :key="index">{{sval.name}} <span style="color:#8591A6 ;font-size: 12px;">{{sval.district}}</span> </li> </ul> <aMap :ref="'aMap'+formobj.prop" :aMapId="'aMapId'+formobj.prop" :location="formData[formobj.prop+'location']" @cbSearch="cbSearch($event,formobj.prop)"></aMap> </div> --> <quillEditor v-if="formobj.quillEditor" :quill="formData[formobj.prop]"></quillEditor> </el-form-item> </el-col> </el-form> </template> <!-- zoutiancong封装,date:20210429,详细使用见根目录@/views/home/testForm/testForm.vue,———————————————————————————————————————————————————————————————————————————————— --> <script> // import aMap from '../../map/aMap.vue' import quillEditor from '@/components/quillEditor/quillEditor.vue' export default { components:{ quillEditor }, props: { formObj: { type: Array, required: true }, formData: { type: Object, required: true }, searchSelectOptionsCb:{ type:Array, } }, data() { let uploadFileUrl = this.$store.state.user.uploadFileUrl; return { uploadUrl:uploadFileUrl, dialogImageUrl: '', searchSelectLoading:false, dialogVisible: false, disabled: false, searchShow: '', //高德地图input收索联想 setSearchVal: [], //高德地图赋值搜索内容 }; }, created() { }, watch:{ }, methods: { //select变化调用 selectChange(value, index, prop) { this.$emit('selectChange', value, index, prop); }, // input的input事件 inputINPUT(value, index, prop){ this.$emit('inputINPUT', value, index, prop); }, // input的change事件 inputChange(value, index,prop){ this.$emit('inputChange', value,index, prop); }, // 搜索类型select搜索 remoteMethod(query,index,prop) { if (query) { this.searchSelectLoading = true; this.$emit('querySelectValue',query,index,prop); setTimeout(() => { this.formObj[index].options = this.searchSelectOptionsCb; this.searchSelectLoading = false; }, 500) } else { this.searchSelectOptios = []; } }, //switch变化 formSwitchChange(val,index,prop){ this.$emit("formSwitchChange",val,index,prop); }, //按钮点击事件 buttonClick(prop,index){ this.$emit("buttonClick",prop,index); }, //文件上传成功回调 uploadSuccess(response,file,fileList,limit,prop,index) { this.formObj[index].uploadObj.hideUpload=fileList.length==limit;//文件列表变化后判断当前文件列表长度是否等于限制长度。目的,当长度相等时隐藏文件上传按钮 this.pushUpload(file,fileList,limit,prop); }, //文件删除 handleRemove(file,fileList,limit,prop,index) { this.formObj[index].uploadObj.hideUpload=fileList.length==limit;//文件删除后判断当前文件列表长度是否等于限制长度。目的,当长度相等时隐藏文件上传按钮 this.pushUpload(file,fileList,limit,prop); }, // 文件预览 handlePictureCardPreview(file) { this.dialogImageUrl = file.url; this.dialogVisible = true; }, //提交时验证表单,直接在父级调用 submitForm() { let formValidate=Boolean; this.$refs.ruleForm.validate((valid) => { if (valid) { formValidate=true; } else { this.$message.warning("请把信息填写完整!"); formValidate = false; } }); return formValidate; }, /* 清空表单 逻辑: 1 、如果要清空文件上传列表,要传入要清空的upload的字段名,假如多个upload用for循环,调用清空方法! 2、清空upload之后,还要把upload上传框展示出来,通过字段名比对,获取到在formObj中的下标,通过下标操作对象属性,进行展示 */ resetForm(uploadArr) { this.$refs.ruleForm.resetFields(); if(uploadArr){ for(let i=0;i<uploadArr.length;i++){ this.$refs[uploadArr[i]][0].clearFiles(); let index=this.formObj.findIndex(item=>item.prop==uploadArr[i]); this.formObj[index].uploadObj.hideUpload=false; } } }, // 单个字段验证 validateFieldProp(prop){ let formValidate=Boolean; this.$refs.ruleForm.validateField(prop,valid => { if (!valid) { formValidate=true; } else { formValidate = false; } }); return formValidate; }, // 对文件上传,删除进行赋值,调用form验证 pushUpload(file, fileList,limit,prop){ if(fileList.length>0){ this.formData[prop]=fileList; }else{ // 表示没有数据,把字段置空 this.formData[prop]=""; } this.$refs.ruleForm.validateField(prop);//调用验证form表单的文件上传 }, //地图input的input事件 aMapInput(value, prop) { this.$refs[`aMap${prop}`][0].getSearch(value); }, //子组件返回地图搜索值 cbSearch(val,prop) { this.setSearchVal = val.tips; //子组件 this.searchShow = prop; //显示input输入联想 }, //选中地图值 selectVal(val,prop,index) { // 赋值的时候,拿到键,及formobj的下标,进行赋值 this.formData[prop] = val.name; //input输入框赋值 this.formData.district = val.district; //传入省市区 let lngLat = { lng: val.location.lng, lat: val.location.lat }; this.formData[`${prop}location`] = lngLat; this.searchShow = ''; //隐藏input输入联想 }, } } </script> <style lang="less" scoped> @width: 220px; form { overflow: hidden; } /deep/.el-input { width: @width; } /deep/.el-select { width: @width; } /deep/.el-date-editor.el-input { width: @width; } /deep/.el-date-editor .el-range-separator{ width: 20px !important; } /deep/.el-range-editor--small.el-input__inner{ width: 400px; } .el-textarea { width: 400px; } .hide { /deep/ .el-upload--picture-card { display: none; } } .amap_div { overflow: hidden; height: 400px; width: 600px; position: relative; .sreach_ul { position: absolute; top: 1; background-color: white; z-index: 9; min-width: 210px; float: auto; height: 200px; overflow: auto; padding: 0 20px; line-height: 24px; } } </style> 

2、父组件调用

<template> <div> <el-button type="primary" @click="dialog = true" size="mini">点击打开 Dialog</el-button> <el-dialog title="提示" :visible.sync="dialog" width="1200px" :modal-append-to-body="false"> <publicForm ref="publicForm" :formObj="formObj" :formData="formData" :searchSelectOptionsCb="searchSelectOptionsCb" @selectChange="selectChange" @inputINPUT="inputINPUT" @inputChange="inputChange" @querySelectValue="querySelectValue" @formSwitchChange="formSwitchChange" @buttonClick="buttonClick"> </publicForm> <span slot="footer" class="dialog-footer"> <el-button type="primary" @click="dialogOK">确认</el-button> <el-button @click="dialog=false">取 消</el-button> </span> </el-dialog> </div> </template> <script> import formJs from './js/testForm.js' export default { components: {}, data() { return { dialog: false, //弹出框 formObj: formJs.formObj, formData: formJs.formData, searchSelectOptionsCb: [], //form表单搜索select返回值 }; }, watch: { dialog(newVal, oldVal) { if (!newVal) { this.$refs.publicForm.resetForm(); //窗口关闭清空表单 } }, }, methods: { // select选择框变化 selectChange(value, index, prop) { console.log(value, index, prop) }, // inpuit变化 inputINPUT(value, index, prop) { console.log(value, index, prop) }, // inpuit Change inputChange(value, index, prop) { console.log(value, index, prop) }, // select 搜索值 querySelectValue(value, index, prop) { console.log(value, index, prop) let arr = [{ label: '搜索返回1号', value: 1 }, { label: '搜索返回2号', value: 2 }]; this.searchSelectOptionsCb = arr; }, // form表单switch变化 formSwitchChange(val, index, prop) { console.log(val, index, prop) }, // 按钮点击 buttonClick(index, prop) { console.log(index, prop) }, dialogOK() { //判断表单验证是否通过 if (this.$refs.publicForm.submitForm()) { console.log("success"); console.log(this.formData) } else { console.log("error") } }, } } </script> <style lang="less" scoped> </style> 

3、父组件js(正则表达式js可以不用,或者自己封装)

import regex from '../../../../utils/regex.js' // 正则表达式 export default { formObj: [{ input: true, //是input label: "input+正则", //字段 prop: "input", //字段名 placeholder: "请填写手机号", //提示内容 width: 12, //参考el-col disabled: false, //是否禁用 unit:'单位', rules: [{ required: true, message: '联系方式' }, { //可以自己写utils,封装正则验证 validator: (rule, value, callback) => { if (!value || !regex.isPhone(value)) { callback(new Error()); } else { callback(); } }, message: "联系方式不对", }] //验证 }, { textarea: true, //是input label: "输入框", //字段 prop: "textearea", //字段名 placeholder: "请填写输入框", //提示内容 width: 12, //参考el-col disabled: false, //是否禁用 rules: [{ required: true, message: '输入框' }, ] //验证 }, { select: true, label: "选择框", prop: "select", placeholder: "请选择", width: 12, //参考el-col disabled: false, options: [{ label: "options1", value: "1" }, { label: "options2", value: "2" }, ], rules: [{ required: true, message: '选择框不能为空!' }] }, { searchSelect: true, label: "select搜索框", prop: "searchSelect", placeholder: "请选择", width: 12, //参考el-col disabled: false, options: [], rules: [{ required: true, message: 'select搜索框!' }] }, { dateTimeRange: true, label: "年月日时分秒开", prop: "dateTimeRange", width: 12, //参考el-col disabled: false, options: { selectableRange: '18:30:00 - 20:30:00' }, rules: [{ required: true, message: '年月日时分秒开' }, ] }, { timePicker: true, label: "时分秒选择器", prop: "timePicker", placeholder: "请选择", width: 12, //参考el-col disabled: false, options: "", rules: [{ required: true, message: '时分秒选择器' }, ] }, { timePickerIsRange: true, label: "时分秒开始结束", prop: "timePickerIsRange", placeholder: "请选择", width: 12, //参考el-col disabled: false, options: "", rules: [{ required: true, message: '时分秒开始结束' }, ] }, { datePicker: true, label: "年月日选择器", prop: "datePicker", placeholder: "请选择", width: 12, //参考el-col disabled: false, options: "", rules: [{ required: true, message: '年月日选择器' }, ] }, { datePickerIsRange: true, label: "年月日开始结束", prop: "datePickerIsRange", placeholder: "请选择", width: 12, //参考el-col disabled: false, options: "", rules: [{ required: true, message: '年月日开始结束' }, ] }, { dateTime: true, label: " 年月日时分秒", prop: "dateTime", placeholder: "请选择", width: 12, //参考el-col disabled: false, options: "", rules: [{ required: true, message: ' 年月日时分秒' }, ] }, { switch: true, label: "switch", prop: "switch", placeholder: "请选择", width: 12, //参考el-col disabled: false, rules: [{ required: true, message: 'switch' }, ] }, { radio: true, label: "单选框", prop: "radio", placeholder: "请选择", width: 12, //参考el-col disabled: false, options: [{ label: "单选框1", value: "1" }, { label: "单选框2", value: "2" }, ], rules: [{ required: true, message: '单选框不能为空' }, ] }, { checkbox: true, label: "复选框", prop: "checkbox", disabled: false, width: 12, //参考el-col options: [{ label: "复选框1", value: "1" }, { label: "复选框2", value: "2" }, { label: "复选框3", value: "3" }, ], rules: [{ required: true, message: '复选框不能为空' }, ] }, { upload: true, label: "文件上传", prop: "upload", disabled: false, uploadObj: { fileType: "2001", limit: 1, //上传长度限制 hideUpload: false, //是否隐藏上传框 }, rules: [{ required: true, message: '文件上传' }, ] }, { button: true, label: "按钮", prop: "buttona", placeholder:"发送验证码", width: 12, //参考el-col disabled: false, }, { text: true, label: "文本", prop: "text", width: 12, //参考el-col disabled: false, }, { quillEditor: true, label: "富文本", prop: "quill", disabled: false, }, ], formData: { input: "", textearea: "", select: "", searchSelect: "", dateTimeRange: [], timePicker: "", timePickerIsRange: [], datePicker: "", datePickerIsRange: [], dateTime: "", date1: "", switch: false, radio: "", checkbox: [], upload: [], text:"这是一段文本,用于预览", quill:{ content:"" } }, } 

4、效果图预览

www.zeeklog.com - elememt form表单二次封装,elform封装,很全很详细
Could not load content