因為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=
