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

29 篇文章 2 订阅
11 篇文章 0 订阅

更新于: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、效果图预览

  • 20
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

邹田聪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值