form表单的二次封装


​ 因为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=


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM