vue3 使用uniapp动态绑定form表单

创建menu目录  index.vue页面和组件components/index页面

最主要的还是组件components/index 里的代码 

<template>
	<view class="form-container">
		<view class="form-box">
			<block v-for="(item,index) in formData" :key="index">
				<uni-section :title="item.label" type="line"
					:sub-title="item.rules.subTiltle + item.limit"></uni-section>
				<!-- 文本框 -->
//name必须为 :name="[index,'value']" 其她的可以用item访问属性
				<uni-forms-item :name="[index,'value']" :required="item.rules.required" :rules='item.rules'
					v-if="item.type=='text' || item.type=='number' || item.type=='password'|| item.type=='textarea'">
					<uni-easyinput :type="item.type" v-model="item.value" :placeholder='item.placeholder'
						@input="inputVal(index)">
						<template v-if="item.rightSlot" v-slot:right>
							<view class="" style="margin-right: 14rpx;">
								{{item.rightSlot}}
							</view>
						</template>
					</uni-easyinput>
				</uni-forms-item>
				<!-- 日期时间 -->
				<uni-forms-item :name="[index,'value']" :rules="[{
						 required: item.rules.required,errorMessage: item.rules.errMess
					}]" v-else-if="item.type=='datetime'|| item.type=='date'||item.type=='daterange'||item.type=='datetimerange'">
					<uni-datetime-picker @change="dataTimeChange($event,index)" :type="item.type"
						return-type="timestamp" v-model="item.value" />
				</uni-forms-item>
				<!-- 单选框-->
				<uni-forms-item :name="[index,'value']" :rules="item.rules" :required="item.rules.required"
					v-else-if="item.type=='radio'">
					<uni-data-checkbox @change="checkBoxChange($event,item,index)" :multiple="item.rules.multiple"
						v-model="item.value" :localdata="item.selectVal" />
				</uni-forms-item>
				<!-- 选择 -->
				<uni-forms-item :name="[index,'value']" v-else-if="item.type=='picker'" :required="item.rules.required"
					:rules="item.rules">
					<picker @change="bindPickerChange($event,item,index)" :value="index" :range="item.selectVal"
						style="height: 100%;" range-key="text">
						<view class=""
							style="padding: 10px; background: #fff;border-radius: 8rpx;border: 1px solid #dcdfe6;">
							{{item.value?item.value:'请选择'}}
						</view>
					</picker>
				</uni-forms-item>
				<!-- 上传图片 -->
				<uni-forms-item :name="[index,'value']" :required="item.rules.required" v-else-if="item.type=='image'">
					<view class="example-body">
						<uni-file-picker v-model="item.value" :limit="item.limit"
							@select="selectHandle($event,index,item)" :value="item.fileLists" @success="handleSuccess"
							@fail="handleFail" @progress="handleProgress"
							:file-mediatype="item.fileMediatype"></uni-file-picker>
					</view>
				</uni-forms-item>
				<!-- 下拉选 -->
				<uni-forms-item :name="[index,'value']" :required="item.rules.required" :rules="item.rules"
					v-else-if="item.type=='select'">
					<uni-data-select v-model="item.value" :localdata="item.selectVal?item.selectVal:getSelectList(item)"
						@change="selectChange($event,item,index)"></uni-data-select>
				</uni-forms-item>
			</block>
		</view>
	</view>
</template>

<script setup>
	import {
		ref
	} from 'vue'
	const emit = defineEmits(["input-val", 'picker-input-btn', 'select-input-btn', 'check-box', 'upload-handle',
		'time-handle'
	])
	const props = defineProps({
		formData: {
			type: Array,
			default: () => []
		},
	})

	function getSelectList(item) {
		// 在这里可以调接口 查询列表
		let list = [{
				value: 0,
				text: "是"
			},
			{
				value: 1,
				text: "否"
			},
		]
		item.selectVal = list
		return list
	}
	// 文本框
	function inputVal(index) {
		emit("input-val", {
			val: props.formData[index].value,
			index: index
		})
	}
	// 选择
	function bindPickerChange(e, item, index) {
		// selectedValue为传给后台的值
		item.selectedValue = e.detail.value
		emit("picker-input-btn", item, index)
	}
	// 单选框
	function checkBoxChange(e, item, index) {
		item.value = e.detail.data.value
		emit("check-box", item, index)
	}
	// 下拉选
	function selectChange(e, item, index) {
		item.selectedValue = e
		emit("select-input-btn", item, index)
	}
	// 上传图片
	function selectHandle(event, index, item) {
		console.log(event, 'selectHandle', index)
		item.fileLists = [{
			url: 'blob:http://localhost:9090/4bacdb76-70d6-426e-9be4-3bca40c5dca2'
		}]
		emit('upload-handle', event.tempFiles, index)
	}

	function handleSuccess(event) {
		console.log('handleSuccess', event.detail.files);
	}

	function handleProgress(event) {
		console.log('handleProgress', event.detail.files);
	}
	// 时间
	function dataTimeChange(val, index) {
		console.log(val, 'val')
		emit('time-handle', val, index)
	}

	function handleFail(error) {
		// 处理文件选择失败的情况
		console.error('handleFail', error);
		// 可以给用户一个错误提示
	}
</script>
<style lang="scss">
	// 弹框
	.select-modal {
		position: fixed;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
		z-index: 300000;

		.select-bg {
			width: 100%;
			height: 100%;
			background: rgba(0, 0, 0, 0.3);
		}

		.select-box {
			position: absolute;
			left: 0;
			bottom: -1000upx;
			width: 100%;
			background: #fff;
			max-height: 50%;
			// height: 0%;
			overflow: auto;

			.select-title {
				display: flex;
				justify-content: space-between;
				height: 80upx;
				background: #f5f5f5;
				line-height: 80upx;
				padding: 0 30upx;
			}

			.select-item {
				font-size: 28upx;
				color: #333;
				border-bottom: 1px solid #eee;
				height: 75upx;
				line-height: 75upx;
				padding: 0 30upx;

				i {
					display: block;
					float: right;
					border-bottom: 4upx solid #1ca032;
					border-right: 4upx solid #1ca032;
					width: 12upx;
					height: 26upx;
					transform: rotate(45deg);
					margin-top: 24.5upx;
				}
			}
		}

		@keyframes mymove {
			0% {
				max-height: 10%;
			}

			100% {
				max-height: 50%;
			}
		}

		/*Safari 和 Chrome:*/
		@-webkit-keyframes mymove {
			0% {
				max-height: 10%;
			}

			100% {
				max-height: 50%;
			}
		}
	}

	// 下拉icon
	.select-icon {
		// display: block;
		float: right;
		border-bottom: 2upx solid #999;
		border-right: 2upx solid #999;
		width: 16upx;
		height: 16upx;
		transform: rotate(-45deg);
		margin-right: 10upx;
	}

	.color-orange {
		color: #ff5b01;
	}

	.color-999 {
		color: #999;
	}

	.font32 {
		font-size: 32upx;
	}

	.plaClass {
		color: #dbdbdb;
	}

	.form-container {
		padding: 0 30upx;

		.form-box {
			width: 100%;
			box-sizing: border-box;
		}

		.colorRed {
			color: red;
		}

		.img-box {
			border-bottom: 1px solid #ededed;
			padding: 30upx 0;

			.update-img-box {
				border: 1px solid #ededed;
				display: flex;

				.update-img {
					width: 140upx;
					height: 140upx;
				}
			}

			.update-img-box2 {
				overflow: hidden;
				display: flex;
			}

			.update-img-box,
			.update-btn-box {
				width: 140upx;
				height: 140upx;
				position: relative;
				margin-top: 20upx;
			}

			.update-img-box .close-img {
				width: 40upx;
				height: 40upx;
				position: absolute;
				right: -12upx;
				top: -16upx;
				background: #fff;
				border-radius: 50%;
			}

			img {
				width: 140upx;
				height: 140upx;
				object-fit: cover;
			}
		}

		.line-right {
			flex: 1;
			height: 100%;
			display: flex;
			align-items: center;
			justify-content: space-between;
			position: relative;

		}

		.send-code-box {
			.send-code {
				font-size: 28upx;
				padding: 0;
				white-space: nowrap;
				// width: 60%;
				//color:#ff5b01;
				height: 90upx;
				line-height: 90upx;
				cursor: pointer;
			}
		}

		.line-left {
			display: flex;
			width: 22%;
			align-items: center;
			height: 100%;
			font-size: 28upx;
			color: #333;
			box-sizing: border-box;
		}

		.img-label {
			width: 100%;
			height: 100%;
			font-size: 28upx;
			color: #333;
			box-sizing: border-box;
		}

		.p-l14 {
			padding-left: 14upx;
		}

		.textarea-box {
			// display: flex;
			border-bottom: 1px solid #ededed;
			padding-top: 20upx;

			// align-items: center;
			textarea {
				height: 150upx;
				font-size: 28upx;
				color: #333;
				width: 100%;
				margin-top: 20upx;
			}
		}

		.line {
			margin-top: 30upx;
			height: 100upx;
			width: 100%;
			margin: 0 auto;
			border-bottom: 1px solid #ededed;
			display: flex;
			overflow: hidden;

			.input {
				padding-right: 20upx;
				height: 100%;
				width: 100%;
				text-align: left;
				font-size: 28upx;
				color: #333;
				border: none;
				overflow: hidden;
				text-overflow: ellipsis;
				outline: none;
			}
		}
	}
</style>

下面是menu/index的代码

<template>
	<view class="menu-style" style="">
		<uni-forms ref="valiForm" :modelValue="formData">
			<form-list :formData="formData" @upload-handle="uploadHandle" @input-val="inputVal"
				@time-handle="timeHandle" @picker-input-btn="pickerInputBtn" @check-box="checkBoxChange"
				@select-input-btn="selectInputBtn"></form-list>
		</uni-forms>
		<view class="buttonBox" @click="submit1">
			提交
		</view>
	</view>
</template>

<script setup>
	import FormList from './components/index'
	import {
		ref
	} from 'vue'
	const valiForm = ref(null)
	const formData = ref([{
			label: "到场拍照反馈",
			type: "image",
			updateImg: false, //默认只显示上传按钮
			fileLists: [],
			name: "presentPhoto",
			value: "",
			limit: 9,
			subTiltle: '最大图片量',
			rules: [{
				errMess: "请上传到场拍照",
				required: true
			}]
		},
		{
			label: "箱内照片",
			type: "image",
			updateImg: false, //默认只显示上传按钮
			fileLists: [],
			name: "inpic",
			value: "",
			limit: 9,
			subTiltle: '最大图片量',
			rules: [{
				errMess: "请上传箱内照片",
				required: true,
			}]
		},
		{
			placeholder: "请输入进口压力",
			label: "进口压力",
			type: "text",
			name: "pressure",
			rightSlot: 'MPa',
			value: "",
			rules: [{
					errorMessage: "请输入进口压力",
					required: true,
				},
				{
					required: true,
					minLength: 2,
					maxLength: 10,
				}
			]
		},
		{
			placeholder: "请选择",
			label: "压力是否正常",
			type: "select",
			selectedValue: '',
			// selectVal: [
			// 	{value:0,text:"是"},
			// 	{value:1,text:"否"},
			// ],
			selectPost: 'pressureType',
			name: "pressureType",
			value: "",
			rules: [{
				required: true,
				errorMessage: "请选择压力是否正常"
			}]
		},
		{
			placeholder: "请选择",
			label: "泄漏",
			type: "select",
			selectedValue: '',
			name: "leakage",
			// selectVal: [
			// 	{value:0,text:"是"},
			// 	{value:1,text:"否"},
			// ],
			value: "",
			selectPost: 'leakage',
			rules: [{
				required: true,
				errorMessage: "请选择是否泄漏"
			}]
		},
		{
			placeholder: "请输入泄漏浓度",
			label: "泄漏浓度",
			type: "text",
			name: "concentration",
			rightSlot: '%LEL',
			value: "",
			rules: [{
					errMess: "请输入泄漏浓度",
					required: false,
				},

				{
					required: false,
					minlength: 1,
					maxlength: 10
				}
			]
		},
	])
	const submitData = ref('')

	function pickerInputBtn(item, index) {
		if (item.selectedValue) {
			formData.value[index].value = item.selectVal[item.selectedValue].text
		}
	}

	function checkBoxChange(item, index) {
		formData.value[index] = item
	}

	function selectInputBtn(item, index) {
		if (item.selectedValue) {
			formData.value[index].value = item.selectVal[item.selectedValue].value
		}
	}

	// 提交表单的函数  
	function submit1() {
		console.log(valiForm, '====')
		valiForm.value.validate().then((res) => {
			console.log('success', res);
			uni.showToast({
				title: `校验通过`
			})
		}).catch((err) => {
			console.log('err', err);
		})
	}

	function inputVal(data2) {
		// var data = JSON.parse(data2);
		console.log(data2)
		if (String(data2.val) != "" && String(data2.index) != "") {
			formData.value[data2.index].value = data2.val;
			console.log(formData.value, '=-==')
		}
	}

	function uploadHandle(tem, index) {

		formData.value[index].value = tem
	}

	function timeHandle(val, index) {
		formData.value[index].value = val
	}
</script>

<style lang="scss" scoped>
	.menu-style {
		padding: 20rpx 0;
		background: #fff;
		margin: 20rpx;
		border-radius: 8rpx;
	}

	.buttonBox {
		width: calc(100% - 40rpx);
		height: 84rpx;
		color: white;
		display: flex;
		align-items: center;
		justify-content: center;
		background-color: #3C9CFF;
		border-radius: 50rpx;
		margin: 20rpx;
		// position: fixed;
		bottom: 50px;
		left: 0;
		right: 0;
		z-index: 999;
	}
</style>

可能有写的不好的地方。多多指教

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值