因为vant提供的组件比较分散,为了高效开发,对form表单封装进行二次封装,将用到的form组件集合成一个文件,统一调用,方便后期项目迭代与维护
功能说明:
-
提供input框输入并验证码发送模块(自定义规则校验-- 纯数字输入,密码输入,文本域,纯文本)
-
提供时间选框(支持日期选择-年月选择-月日选择,年月日选择)
-
提供下拉选框
-
提供头像上传功能(多图片上传,大图预览,上传图片数量限制,默认提示图片)
-
手机评分模块
-
单选框组(默认选中,排列方向--横向/纵向)
-
复选框组(默认选中,排列方向--横向/纵向,复选框形状)
-
步进器(购物车数量增加减少的模块)
-
支持多个form表单的展示
-
支持展示每一个form表单的title标题(可选位置,form表单顶部和底部,左对齐,居中,右对齐)
-
支持展示提交按钮
form表单案例 <template> <div class="home"> <SeForm :searchData="registData" :formList="formList" ></SeForm> </div> </template> <script> import SeForm from '@/views/components/SeForm.vue' export default { name: 'Home', components: { SeForm }, data () { return { registData: { accountName: '', accountCardNo: '', accountSubBank: '', email: '' }, formList:[ { id: '1', title: '', searchForm: [ { prop: 'accountName', placeholder: '请填写开户姓名', name: '开户姓名', type: 'text', rules: [ { required: true, message: '', trigger: 'onBlur' }, ] }, { prop: 'accountCardNo', placeholder: '请填写开户账号', name: '开户账号', type: 'text', rules: [ // { required: true, message: '', trigger: 'onBlur' }, { validator: this.vaildAccountCard, message: '请填写开户账号', trigger: 'onBlur' } ] }, { prop: 'accountSubBank', placeholder: '请填写开户银行', type: 'text', name: '开户银行', rules: [ { required: true, message: '', trigger: 'onBlur' }, ] }, { prop: 'email', placeholder: '请填写邮箱', type: 'text', name: '邮箱', rules: [ { validator: this.vaildEmail, message: '请填写邮箱', trigger: 'onBlur' } ] }, ] } ] } }, methods:{ vaildEmail(val) { if(!val) { Toast('请输入邮箱') return false } const rule =/^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/ let result = rule.test(val) if(result) { return result }else { Toast('请输入正确的邮箱') return result } }, vaildAccountCard(val) { if(!val) { Toast('请输入开户账号') return false } const rule =/^\d+$/ const str = val.replace(/\s+/g,'') let result = rule.test(str) if(result) { return result }else { Toast('请输入正确的开户账号') return result } }, } } </script> <style scoped lang="less"></style>
form表单的内部封装 <template> <van-form ref="vantForm" validate-first @submit="onSubmit" @failed="onFailed"> <!-- list结构的form表单start --> <template v-for="val in formList"> <div :key="val.id" class="vant_form"> <div v-if="isClass === '1' " class="form_list_title"> <span>{{ val.title }}</span> </div> <template v-for="item in val.searchForm"> <!-- input文本框部分 --> <div class="filed_box" :key="item.prop"> <template v-if=" [ 'text', 'tel', 'digit', 'number', 'textarea', 'password' ].indexOf(item.type) !== -1 " > <van-field v-model.trim="searchData[item.prop]" :name="item.name" :type="item.type" :placeholder="item.placeholder" :disabled="item.disabled ? item.disabled : false" :rules="item.rules" :label="item.name" /> </template> <template v-if="['verCode'].indexOf(item.type) !== -1"> <van-field v-model="searchData[item.prop]" center clearable :label="item.name" :rules="item.rules" :name="item.name" :disabled="item.disabled ? item.disabled : false" :placeholder="item.placeholder" > <template #button> <van-button size="small" type="primary" :disabled="codeShow" @click.stop.prevent="getCode" >{{ codeText }}</van-button > </template> </van-field> </template> <!-- 时间选择 --> <template v-if=" [ 'date', 'year-month', 'month-day', 'time', 'datetime', 'datehour' ].indexOf(item.type) !== -1 " > <van-field readonly clickable :name="item.type" :value="searchData[item.prop]" :label="item.name" :placeholder="item.placeholder" @click="showPicker = true" /> <van-popup v-model="showPicker" position="bottom"> <van-datetime-picker :type="item.type" @confirm="onConfirm(item, $event)" @cancel="showPicker = false" /> </van-popup> </template> <!-- 选择器 --> <template v-if="['picker'].indexOf(item.type) !== -1"> <van-field readonly clickable :name="item.type" :value="searchData[item.prop]" :label="item.name" :placeholder="item.placeholder" @click="showSelectPicker = true" /> <van-popup v-model="showSelectPicker" position="bottom"> <van-picker show-toolbar :columns="item.columns" @confirm="SelectConfirm(item, $event)" @cancel="showSelectPicker = false" /> </van-popup> </template> <!-- 头像上传 --> <template v-if="['uploaderImg'].indexOf(item.type) !== -1"> <van-field :name="item.type" :label="item.name"> <template #input> <van-uploader v-model="searchData[item.prop]" :max-count="item.maxCount" :before-read="beforeRead" :after-read="afterRead" @click-preview="clickPreview" @click.native.stop="click(item)" > <div class="van-uploader__upload"> <!-- 是否显示自定义上传的提示图片 --> <span v-if="item.modelImg" class="van-icon"> <img :src="item.modelImg" alt="" /> </span> <span v-else></span> <input multiple="multiple" type="file" accept="image/*" class="van-uploader__input" /> </div> </van-uploader> </template> </van-field> </template> <!-- 评分模块 --> <template v-if="['rate'].indexOf(item.type) !== -1"> <van-field :name="item.type" :label="item.name"> <template #input> <van-rate v-model="searchData[item.prop]" /> </template> </van-field> </template> <!-- 单选框组 --> <template v-if="['radioGroup'].indexOf(item.type) !== -1"> <van-field :name="item.type" :label="item.name"> <template #input> <van-radio-group v-model="searchData[item.prop]" :direction="item.direction" > <van-radio v-for="(ele, indx) in item.options" :key="indx" :name="ele.value" > {{ ele.label }} </van-radio> </van-radio-group> </template> </van-field> </template> <!-- 复选框组 --> <template v-if="['checkboxGroup'].indexOf(item.type) !== -1"> <van-field :name="item.type" :label="item.name"> <template #input> <van-checkbox-group v-model="searchData[item.prop]" :direction="item.direction" > <van-checkbox v-for="(ele, indx) in item.options" :key="indx" :name="ele.value" :shape="item.shape" >{{ ele.label }}</van-checkbox > </van-checkbox-group> </template> </van-field> </template> <template v-if="['stepper'].indexOf(item.type) !== -1"> <van-field :name="item.type" :label="item.name"> <template #input> <van-stepper v-model="searchData[item.prop]" /> </template> </van-field> </template> </div> </template> <div v-if="isClass === '2' " :class="['form_list_title',val.className]"> <span>{{ val.title }}</span> </div> </div> </template> <div style="margin-top: 0.16rem;" v-if="submitShow"> <van-button round block type="info" native-type="submit"> {{ btnName }} </van-button> </div> <slot></slot> </van-form> </template> <script> import Moment from 'moment' import { ImagePreview } from 'vant' export default { name: 'SeFormModel', props: { searchData: { type: Object, default: () => {} }, formList: { type: Array, default: () => [] }, submitShow: { type: Boolean, default: () => false }, btnName: { type: String, default: () => '登录' }, codeShow: { type: Boolean, default: () => false }, isClass: { type: String, default: () => '2' }, codeText:{ type: String, default:()=>'获取验证码' } }, data () { return { showPicker: false, //时间组件的显示隐藏 showSelectPicker: false, // 选择器的显示隐藏 propType: '' } }, methods: { /** * @function onConfirm * @description 时间选择组件的确定赋值 */ onConfirm (item, time) { this.searchData[item.prop] = Moment(time).format('YYYY-MM-DD') this.showPicker = false }, /** * @function SelectConfirm * @description select选择器确定赋值 */ SelectConfirm (item, value) { this.searchData[item.prop] = value this.showSelectPicker = false }, /** * @function onOversize * @description 上传头像,显示图片的大小 */ onOversize (file) { console.log(file) this.$toast('文件大小超过限制500kb') }, /** * @function beforeRead * @description 上传前,显示图片格式 */ beforeRead (file) { console.log(1234) // accept=".png,.PNG,.jpeg,.jpg,.JPG" if ( file.type !== 'image/jpeg' && file.type !== 'image/png' && file.type !== 'image/jpg' && file.type !== 'image/gif' ) { this.$toast('请上传 jpg,png 格式图片') return false } return true }, /** * @function afterRead * @description 文件上传完完毕之后的回调 */ afterRead (file) { file.status = 'uploading' file.message = '加载...' this.$emit('uploadImg', [file, this.propType]) }, click (item) { this.propType = item.prop }, clickPreview (val) { ImagePreview({ images: [val.url], closeable: true }) }, onSubmit (values) { this.$emit('submit', this.searchData) }, onFailed (errorInfo) { console.log('failed', errorInfo) }, getCode () { this.$emit('getCode') } } } </script> <style scoped lang="less"> .vant_form { border-radius: 0.1rem; overflow: hidden; } .van-uploader__upload { position: relative; width: 100%; > span { display: inline-block; width: 100%; height: 100%; > img { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 30%; height: 50%; } } } ::v-deep .van-uploader__input-wrapper { width: 100%; } </style>
点击看看为青年律师报薪:https://fhui.qingcongai.com/activity?hmsr=%E5%8D%9A%E5%AE%A2%E5%9B%AD&hmpl=&hmcu=&hmkw=&hmci=