uni-app开发——基于uni-forms和ThorUI简单封装的表单组件

本文探讨了uni-app在开发中的表单处理问题,尤其是针对申报页面的常见设计,提出了进行公共部分封装的需求。作者分享了在封装过程中遇到的挑战,如UI组件的不成熟,特别是ThorUI的时间格式和方法调用等问题,并鼓励读者交流解决方案。

uni-app出现较长时间了,优势也是不言而喻(一次开发能应用小程序、app、网页等),但一直觉得伴随其出现的UI组件相当不成熟,开发起来总是遇到很多难题。
这里描述一下uni-app开发中表单的处理,页面样式大体:
在这里插入图片描述
在这里插入图片描述
废话也不多说了,类似这种的申报页面多的很,那肯定要提取公共部分进行封装咯。
大体借鉴一下思想吧,此处代码多是应对本次项目开发,不具备 多项目的一般性

<!-- **基于uni-forms和ThorUI简单封装的表单组件**
	**itemsDatas的prop 对应的是 fromData的数据字段**
	**注意:码表部分prop对应其name,value对应其码值,dict_key为码表类型,hidden是否展示行**
-->
<template>
	<uni-forms class="formStyle" ref="form" :value="formData" :rules="rules">
		<block v-for="item in itemsDatas" :key="item.label + item.prop">
			<!-- title样式,a标签做锚点 -->
			<view class="formTitle" v-if="item.type==='headTitle'&&item.hidden!==false">
				<a :name="item.label"></a>
				<view class="tit">{{item.label}}</view>
				<view class="discri">{{item.prop}}</view>
			</view>
			<!-- 基本input -->
			<uni-forms-item class="side-padding" :name="item.prop" :required="item.required||false" :label="item.label" v-else-if="item.type==='input'&&item.hidden!==false">
				<input :disabled="formData.disabled || item.disabled || false" type="text" v-model="formData[item.prop]" class="uni-input-border" placeholder-style="font-size: 32rpx;color:#CCCCCC;text-align: right;" @blur="binddata(item.prop, $event.detail.value)" :placeholder="item.placeholder||'请输入'" />
			</uni-forms-item>
			<!-- 嵌套底部弹出层和列表选项 -->
			<uni-forms-item class="side-padding" :name="item.prop" :required="item.required||false" :label="item.label" v-else-if="item.type==='actionsheet'&&item.hidden!==false">
				<input :disabled="formData.disabled || false" type="text" v-model="formData[item.prop]" class="uni-input-border" placeholder-style="font-size: 32rpx;color:#CCCCCC;text-align: right;" @focus="getsyscode(item)" @blur="binddata(item.prop, $event.detail.value)" :placeholder="item.placeholder||'请选择'" />
				<tui-actionsheet  
				  :show="item.showActionSheet || false" 
				  :item-list=" item.itemList||'' " 
				  @click="itemClick($event,item)" 
				  @cancel="()=>{item.showActionSheet=false}">
				</tui-actionsheet>
			</uni-forms-item>
			<!-- 底部弹出时间选择,年月日 -->
			<uni-forms-item class="side-padding" :name="item.prop" :required="item.required||false" :label="item.label" v-else-if="item.type==='date'&&item.hidden!==false">
				<input :disabled="formData.disabled || false" type="text" v-model="formData[item.prop]" class="uni-input-border" placeholder-style="font-size: 32rpx;color:#CCCCCC;text-align: right;" @focus="showDate(item.prop)" @blur="binddata(item.prop, $event.detail.value)" :placeholder="item.placeholder||'请选择'" />
				<tui-datetime :ref="item.prop" @confirm="change($event,item)" :type="2"></tui-datetime>
			</uni-forms-item>
			<!-- 单选checkbox -->
			<uni-forms-item class="side-padding" :name="item.prop" :required="item.required||false" :label="item.label" v-else-if="item.type==='checkbox'&&item.hidden!==false">
				<checkbox-group :disabled="formData.disabled || false" class="textRight" @change="binddata(item.prop, $event.detail.value)">
					<label>
						<checkbox value="1" :checked="formData[item.prop]" />{{item.context}}
					</label>
				</checkbox-group>
			</uni-forms-item>
			
			<!-- 自定义样式 -->
			<view v-else-if="item.type==='custom'">
				<slot
				  :name="item.prop"
				  :item="item"
				  :form-data="formData"
				/>
			</view>
		</block>
		
		<block>
			<view class="footerStyle">
				<slot />
			</view>
		</block>
	</uni-forms>
</template>

<script>
	export default{
		props:{
			formData: {
			  type: Object,
			  default: () => {}
			},
			rules: {
			  type: Object,
			  default: () => {}
			},
			itemsDatas: {
			  type: Array,
			  default: () => []
			},
		},
		methods:{
			/**获取码表*/
			getsyscode(item) {
				item.showActionSheet=true
				if (item.dict_key) { // 码表类型不为空时执行,为空则默认读取静态数据
					this.$getType(item.dict_key, res => {
						item.itemList = res.map(item => {
							return {
								value: item.id,
								text: item.text,
								color: "#2B2B2B"
							}
						})
						
					})
				}
				
			},
			/** tui-actionsheet方法封装
				获取操作菜单各项值*/
			itemClick(index,item) {
				let i = index.index
				this.formData[item.prop] = item.itemList[i].text // 码表name
				this.$refs.form.setValue(this.formData[item.prop],item.itemList[i].text)
				this.formData[item.value] = item.itemList[i].value // 码值
				this.$refs.form.setValue(this.formData[item.value],item.itemList[i].value)
				item.showActionSheet=false
			},
			/** 日期 */
			showDate(edot){
				// this.$refs[edot].show();
				this.$refs[edot][0].isShow = true;
			},
			/**选择的结果
			e:{
				day: "07"
				month: "04"
				result: "2021-04-07"
				year: 2021
			}
			*/
			change(e,item) {
				this.formData[item.prop] = e.result
				this.$refs.form.setValue(this.formData[item.prop],e.result)
				this.$forceUpdate() // 回显有点问题,加了一个强制更新
			},
			
		}
	}
</script>

<style lang="scss" scoped>
	.formStyle{
		box-sizing: border-box;
		background-color: #fff;
		.side-padding{
			padding: 0 30rpx;
		}
	}
	.uni-input-border {
			padding: 0 10px;
			height: 35px;
			width: 100%;
			font-size: 32rpx;
			color: #333300;
			box-sizing: border-box;
		}
	.formTitle{
		border-top: 20rpx #E6E6E6 solid;
		padding: 30rpx;
		.tit{
			font-size: 32rpx;
			font-weight: 600;
			color: #333333;
			line-height: 45rpx;
		}
		.discri{
			font-size: 28rpx;
			font-weight: 400;
			color: #666666;
			line-height: 44rpx;
			margin-top: 30rpx;
		}
	}
	.footerStyle{
		box-sizing: border-box;
		padding: 60rpx 30rpx;
	}
	.textRight{
		text-align: right;
		font-size: 30rpx;
		font-weight: 400;
		color: #333333;
		line-height: 42rpx;
	}
	/deep/.uni-forms-item__inner{
		padding-bottom: 27rpx;
		padding-top: 27rpx;
		border-bottom: 1rpx #E6E6E6 solid;
	}
	/deep/.uni-input-input{
		text-align: right;
	}
</style>

像头部啊,headTitle部分,就是自定义的,但是这里项目较多体现就直接写里面了,还有ThorUI组件的一些坑,比如时间格式的间隔符“-”、“/”,就没找到好的方式转化,以及它官方文档里的show()方法没法调用,最后自己去$refs找到的,其他等等,不一一列了,有问题,多交流。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值