vue+elementUI实现表单和图片上传及验证功能示例

(编辑:jimmy 日期: 2024/11/18 浏览:2)

本文实例讲述了vue+elementUI实现表单和图片上传及验证功能。分享给大家供大家参考,具体如下:

最终实现需求如下图:

form表单内容与重点人员图片同时上传且图片为必填项

vue+elementUI实现表单和图片上传及验证功能示例

分析弹框页需要解决的问题有:

1、表单内容的验证及必填项

2、新增和编辑用同一个组件如何处理数据

3、图片需要和信息一起传递(即不允许自动上传)

4、图片必填的验证问题

针对上述问题作出方案:

1、el-form的表单验证需要注意几个地方:

a:el-form-item的prop值需要和表单标签的v-model值保持一致

例如:

<el-form-item label="姓名:" prop="name">
 <el-input style="width:1rem;" v-model="addKeyPersonForm.name" placeholder="请输入姓名"></el-input>
</el-form-item>

b:验证规则有直接用element官网提供的也有自定义的

例如:其中checkNumber就是自定义的验证数字的正则

rules: { // 表单验证
 name: [
  { required: true, message: '必填项', trigger: 'blur' }
 ],
 age: [
  { required: true, message: '必填项', trigger: 'blur' },
  { validator: checkNumber, trigger: 'blur' }
 ],
 sex: [
  { required: true, message: '必填项', trigger: ['blur', 'change'] }
 ],
 nationlity: [
  { required: true, message: '必填项', trigger: ['blur', 'change'] }
 ],
 userType: [
  { required: true, message: '必填项', trigger: ['blur', 'change'] }
 ],
 idCard: [
  { required: true, message: '必填项', trigger: 'blur' },
  { validator: checkIdCard, trigger: 'blur' }
 ],
 registered: [
  { required: true, type: 'array', message: '必填项', trigger: ['blur', 'change'] }
 ],
 registeredDetails: [
  { required: true, message: '必填项', trigger: 'blur' }
 ],
 domicile: [
  { required: true, type: 'array', message: '必填项', trigger: ['blur', 'change'] }
 ],
 domicileDetails: [
  { required: true, message: '必填项', trigger: 'blur' }
 ],
 file: [
  { required: true, message: '请上传图片' }
 ],
 plateNumber: [
  { validator: checkPlateNum, trigger: 'change' }
 ]
}

2、新增和编辑问题需要我们在打开组件的时候传递两个值

props: {
 dialogType: { //是新增还是编辑,用于判断
  type: String
 },
 keypersonList: { //表单的原始值
  type: Object
 }
}

3、图片和form表单内容一起上传

首先我们需要阻止图片的自动上传让它等到我们点击保存按钮的时候再一起传给后台

我们看这段代码就是图片上传组件

<el-upload class="upload-img"
      :style="{backgroundImage:'url(' + dialogImageUrl + ')', backgroundRepeat:'no-repeat', backgroundPosition:'center center', backgroundSize: 'contain'}"
      ref="uploadxls"
      action="aaa"
      ::limit="1"
      :show-file-list="false"
      :on-change="handlePictureCardPreview"
      :before-upload="beforeupload"
      accept="image/png,image/gif,image/jpg,image/jpeg">
 <i v-show="!dialogImageUrl" class="el-icon-upload avatar-uploader-icon"></i>
 <div v-show="!dialogImageUrl" slot="tip" class="el-upload__text upload__tip">上传照片</div>
</el-upload>

action我们随便填一个就好,重点是这一句:before-upload="beforeupload"在图片上传之前执行beforeupload方法在里面return false就可以实现阻止upload自动上传

// 阻止upload的自己上传,进行再操作
beforeupload (file) {
 this.formData.append('file', file)
 return false
}

关于图片和表单文件一起上传我们选择了formData格式存储数据用于上传

选择了图片并填写必填信息之后点击保存进行上传操作,在onSubmit方法里把表单信息都append到formData里that.$refs.uploadxls.submit() // 提交时触发了before-upload函数--》完成图片的上传即执行beforeupload方法

4、图片必填的验证问题:

a、如果没有选择图片点击保存则图片提示:请上传图片

vue+elementUI实现表单和图片上传及验证功能示例

b、此时选择了图片则“请上传图片”消失

vue+elementUI实现表单和图片上传及验证功能示例

验证规则里有一条file就是做图片必填验证的

file: [
 { required: true, message: '请上传图片' }
]

c、在编辑重点人员信息时重点人员图片已存在没有进行图片上传操作此时点击保存应该不提示“请上传图片”,未解决这个问题我们在上传时添加判断:

如果是编辑信息且未进行过图片上传操作则去掉file验证

就是以下代码

that.rules.file = [{ required: true, message: '请上传图片' }]
if (that.dialogType !== 'add' && !this.doUpload) {
 that.rules.file = []
 that.$refs['uploadElement'].clearValidate()
}

整个弹框组件的代码如下:

<template>
  <div class="add-keyperson-dialog">
   <el-form :inline="true"
        ref="addKeyPersonForm"
        :model="addKeyPersonForm"
        class="demo-form-inline"
        label-width="1.4rem"
        :rules="rules">
    <el-form-item label="姓名:" prop="name">
     <el-input style="width:1rem;" v-model="addKeyPersonForm.name" placeholder="请输入姓名"></el-input>
    </el-form-item>
    <el-form-item label="性别:" label-width="0.64rem" prop="sex">
     <el-select style="width:0.65rem;" v-model="addKeyPersonForm.sex" placeholder="请选择">
      <el-option label="男" value="1"></el-option>
      <el-option label="女" value="2"></el-option>
     </el-select>
    </el-form-item>
    <el-form-item label="年龄:" label-width="0.64rem" prop="age">
     <el-input style="width:0.65rem;" v-model="addKeyPersonForm.age" placeholder="请输入"></el-input>
    </el-form-item>
    <el-form-item prop="file" class="upload-img-form" ref="uploadElement">
     <el-upload class="upload-img"
           :style="{backgroundImage:'url(' + dialogImageUrl + ')', backgroundRepeat:'no-repeat', backgroundPosition:'center center', backgroundSize: 'contain'}"
           ref="uploadxls"
           action="aaa"
           ::limit="1"
           :show-file-list="false"
           :on-change="handlePictureCardPreview"
           :before-upload="beforeupload"
           accept="image/png,image/gif,image/jpg,image/jpeg">
      <i v-show="!dialogImageUrl" class="el-icon-upload avatar-uploader-icon"></i>
      <div v-show="!dialogImageUrl" slot="tip" class="el-upload__text upload__tip">上传照片</div>
     </el-upload>
    </el-form-item>
    <!--<img :src="/UploadFiles/2021-04-02/dialogImageUrl">


<script>
import options from '../../../static/js/country-data.js'
import PersonnelControlAdd from './PersonnelControlAdd.vue'
import axiosMap from './../../api/map'
import axiosControl from './../../api/control'
import PersonnelAddPosition from './PersonnelAddPosition.vue'
export default {
 components: {
  PersonnelAddPosition,
  PersonnelControlAdd},
 name: 'add-keyperson-dialog',
 props: {
  dialogType: {
   type: String
  },
  keypersonList: {
   type: Object
  }
 },
 computed: {
  position: { // 经纬度
   // getter
   get: function () {
    let str = ''
    if (this.addKeyPersonForm.longitude !== '' && this.addKeyPersonForm.latitude !== '' && this.addKeyPersonForm.longitude !== null && this.addKeyPersonForm.latitude !== null) {
     str = this.addKeyPersonForm.longitude + ',' + this.addKeyPersonForm.latitude
    }
    return str
   },
   // setter
   set: function (newValue) {
   }
  }
 },
 /* watch: {
  keypersonList: { // 深度监听,可监听到对象、数组的变化
   handler (newQuestion, oldQuestion) {
    this.addKeyPersonForm = Object.assign({}, this.keypersonList)
    this.dialogImageUrl = Object.assign({}, this.keypersonList).iconUrl
   },
   deep: true
  }
 }, */
 data () {
  var checkNumber = (rule, value, callback) => {
   let regEn = /^[1-9]\d*$/
   if (!regEn.test(value)) {
    callback(new Error('正整数'))
   } else {
    callback()
   }
  }
  var checkIdCard = (rule, value, callback) => {
   let regEn = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
   if (!regEn.test(value)) {
    callback(new Error('请输入正确身份证'))
   } else {
    // 校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10
    // 下面分别分析出生日期和校验位
    let num = value.toUpperCase()
    let len, re
    len = num.length
    if (len === 15) {
     re = new RegExp(/^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/)
     let arrSplit = num.match(re) // 检查生日日期是否正确
     let dtmBirth = new Date('19' + arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4])
     let bGoodDay
     bGoodDay = (dtmBirth.getYear() === Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) === Number(arrSplit[3])) && (dtmBirth.getDate() === Number(arrSplit[4]))
     if (!bGoodDay) {
      callback(new Error('请输入正确身份证'))
     } else { // 将15位身份证转成18位 //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10
      let arrInt = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
      let arrCh = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
      var nTemp = 0, i
      num = num.substr(0, 6) + '19' + num.substr(6, num.length - 6)
      for (i = 0; i < 17; i++) {
       nTemp += num.substr(i, 1) * arrInt[i]
      }
      num += arrCh[nTemp % 11]
      callback()
     }
    }
    if (len === 18) {
     re = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/)
     let arrSplit = num.match(re) // 检查生日日期是否正确
     let dtmBirth = new Date(arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4])
     let bGoodDay
     bGoodDay = (dtmBirth.getFullYear() === Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) === Number(arrSplit[3])) && (dtmBirth.getDate() === Number(arrSplit[4]))
     if (!bGoodDay) {
      callback(new Error('请输入正确身份证'))
     } else { // 检验18位身份证的校验码是否正确。 //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10
      let valnum
      let arrInt = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
      let arrCh = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
      var nTemp = 0, i
      for (i = 0; i < 17; i++) {
       nTemp += num.substr(i, 1) * arrInt[i]
      }
      valnum = arrCh[nTemp % 11]
      if (!isNaN(num.substr(17, 1))) {
       callback()
      }
      if (valnum !== num.substr(17, 1)) {
       callback(new Error('请输入正确身份证'))
      }
     }
    }
   }
  }
  var checkPlateNum = (rule, value, callback) => {
   if (value && value !== '') {
    let regEn = /(^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$)/
    if (!regEn.test(value)) {
     callback(new Error('请输入正确车牌号'))
    } else {
     callback()
    }
   } else {
    callback()
   }
  }
  return {
   doSubmitFlag: false,
   showPosition: false,
   doUpload: false,
   keyPersonType: [], // 重点人员类型列表
   addKeyPersonForm: Object.assign({}, this.keypersonList),
   positionForm: {
    longtitude: this.keypersonList.longitude,
    latitude: this.keypersonList.latitude
   },
   options: options, // 存放城市数据,
   innerVisible: false, // 继续添加弹框
   dialogImageUrl: Object.assign({}, this.keypersonList).iconUrl, // 图片
   formData: new FormData(),
   rules: { // 表单验证
    name: [
     { required: true, message: '必填项', trigger: 'blur' }
    ],
    age: [
     { required: true, message: '必填项', trigger: 'blur' },
     { validator: checkNumber, trigger: 'blur' }
    ],
    sex: [
     { required: true, message: '必填项', trigger: ['blur', 'change'] }
    ],
    nationlity: [
     { required: true, message: '必填项', trigger: ['blur', 'change'] }
    ],
    userType: [
     { required: true, message: '必填项', trigger: ['blur', 'change'] }
    ],
    idCard: [
     { required: true, message: '必填项', trigger: 'blur' },
     { validator: checkIdCard, trigger: 'blur' }
    ],
    registered: [
     { required: true, type: 'array', message: '必填项', trigger: ['blur', 'change'] }
    ],
    registeredDetails: [
     { required: true, message: '必填项', trigger: 'blur' }
    ],
    domicile: [
     { required: true, type: 'array', message: '必填项', trigger: ['blur', 'change'] }
    ],
    domicileDetails: [
     { required: true, message: '必填项', trigger: 'blur' }
    ],
    file: [
     { required: true, message: '请上传图片' }
    ],
    plateNumber: [
     { validator: checkPlateNum, trigger: 'change' }
    ]
   }
  }
 },
 created () {
  this.getKeyPersonType()
 },
 methods: {
  handleChange (value) {
  },
  // 获取重点人员类型
  getKeyPersonType: function () {
   let that = this
   let param = {
    typeCodes: 'userType'
   }
   axiosMap.getKeyPersonType(param)
    .then(res => {
     if (res.data.code === 200) {
      that.keyPersonType = res.data.rows['0'].userType
      that.keyPersonType.forEach(function (item) {
       if (that.addKeyPersonForm.userType === item.dataValue) {
        that.addKeyPersonForm.userType = item.dataKey
       }
      })
      // that.keyPersonType.unshift({dataValue: '全部', dataKey: ''})
     } else {
      that.$message.error({
       message: res.data.message
      })
     }
    })
  },
  // 添加控制人员
  addPerson (person) {
   this.addKeyPersonForm.controller.push(person)
  },
  // 添加经纬度
  addPosition (position) {
   this.addKeyPersonForm.longitude = position[0]
   this.addKeyPersonForm.latitude = position[1]
   this.showPosition = false
  },
  // 删除某个控制人员
  deleteRow (index) {
   this.addKeyPersonForm.controller.splice(this.addKeyPersonForm.controller[index], 1)
  },
  // 关闭新增控制人员
  closeFun () {
   this.$refs.addForm.$refs.controlForm.resetFields()
   this.innerVisible = false
  },
  // 关闭经纬度
  closePosition () {
   // this.$refs.addPosition.$refs.addPosition.resetFields()
   this.showPosition = false
  },
  // 图片预览
  handlePictureCardPreview (file) {
   this.dialogImageUrl = file.url
   this.addKeyPersonForm.file = file.url
   this.doUpload = true
   this.$refs['addKeyPersonForm'].validateField('file')
  },
  // 阻止upload的自己上传,进行再操作
  beforeupload (file) {
   this.formData.append('file', file)
   return false
  },
  // 上传重点人员信息
  onSubmit: function () {
   let that = this
   that.formData = new FormData()
   that.rules.file = [{ required: true, message: '请上传图片' }]
   if (that.dialogType !== 'add' && !this.doUpload) {
    that.rules.file = []
    that.$refs['uploadElement'].clearValidate()
   }
   that.$refs['addKeyPersonForm'].validate((valid) => {
    if (valid) {
     that.formData.append('name', that.addKeyPersonForm.name)
     if (that.addKeyPersonForm.sex === '男') {
      that.addKeyPersonForm.sex = 1
     } else if (that.addKeyPersonForm.sex === '女') {
      that.addKeyPersonForm.sex = 2
     }
     that.formData.append('sex', that.addKeyPersonForm.sex)
     that.formData.append('age', that.addKeyPersonForm.age)
     that.formData.append('idCard', that.addKeyPersonForm.idCard)
     that.formData.append('nationlity', that.addKeyPersonForm.nationlity)
     that.formData.append('plateNumber', that.addKeyPersonForm.plateNumber)
     that.formData.append('userType', that.addKeyPersonForm.userType)
     that.formData.append('longitude', that.addKeyPersonForm.longitude)
     that.formData.append('latitude', that.addKeyPersonForm.latitude)
     that.formData.append('registered', that.addKeyPersonForm.registered.join('-'))
     that.formData.append('registeredDetails', that.addKeyPersonForm.registeredDetails)
     that.formData.append('domicile', that.addKeyPersonForm.domicile.join('-'))
     that.formData.append('domicileDetails', that.addKeyPersonForm.domicileDetails)
     that.formData.append('problem', that.addKeyPersonForm.problem)
     that.formData.append('measure', that.addKeyPersonForm.measure)
     that.formData.append('controller', JSON.stringify(that.addKeyPersonForm.controller))
     that.formData.append('remark', that.addKeyPersonForm.remark)
     if (that.dialogType === 'add') {
      that.$refs.uploadxls.submit() // 提交时触发了before-upload函数
      that.doSubmitFlag = true
      axiosControl.saveNewKeyPerson(that.formData)
       .then(res => {
        that.doSubmitFlag = false
        if (res.data.code === 200) {
         that.$message({
          type: 'success',
          message: '添加成功'
         })
         that.$refs.addKeyPersonForm.dialogImageUrl = 'none'
         that.$refs.uploadxls.clearFiles()
         that.$refs.addKeyPersonForm.resetFields()
         that.fileName = ''
         that.uploadForm = new FormData()
         that.$emit('savePersonSuccess')
        } else {
         that.$message.error({
          message: res.data.message
         })
        }
       })
       /* .catch(err => {
        that.$message.error({
         message: err
        })
       }) */
     } else {
      if (!that.doUpload) {
       that.formData.append('iconUrl', that.addKeyPersonForm.iconUrl)
      }
      // 还要传id
      that.formData.append('id', that.addKeyPersonForm.id)
      that.doSubmitFlag = true
      axiosControl.saveEditKeyPerson(that.formData)
       .then(res => {
        that.doSubmitFlag = false
        if (res.data.code === 200) {
         that.$message({
          type: 'success',
          message: '添加成功'
         })
         that.$refs.addKeyPersonForm.dialogImageUrl = 'none'
         that.$refs.uploadxls.clearFiles()
         that.$refs.addKeyPersonForm.resetFields()
         that.fileName = ''
         that.uploadForm = new FormData()
         that.$emit('savePersonSuccess')
        } else {
         that.$message.error({
          message: res.data.message
         })
        }
       })
     }
    } else {
     this.$message({
      type: 'warning',
      message: '请填写正确格式'
     })
     return false
    }
   })
  }
 }
}
</script>

<style scoped>
 .add-keyperson-dialog{
  position:relative;
  height:7.2rem;
  overflow:auto;
 }
 .add-keyperson-dialog .demo-form-inline{
  font-size:0.13rem;
  color:#666;
 }
 /*上传图片样式*/
 .add-keyperson-dialog .upload-img-form{
  width: 1rem;
  height: 1.35rem;
  position: absolute;
  right:0.2rem;
  top:0rem;
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  text-align: center;
 }
 .add-keyperson-dialog .upload-img{
  width: 1rem;
  height: 1.35rem;
  overflow:hidden;
 }
 .add-keyperson-dialog .upload-img:hover {
  border-color: #409EFF;
  color: #409EFF;
 }
 .add-keyperson-dialog .avatar-uploader-icon {
  position:relative;
  z-index:100;
  font-size: 0.3rem;
  color: #8c939d;
  width: 0.9rem;
  height: 1.35rem;
  line-height: 1rem;
  text-align: center;
 }
 .add-keyperson-dialog .upload-img:hover .avatar-uploader-icon {
  color: #409EFF
 }
 .add-keyperson-dialog .avatar {
  width: 100%;
  height: auto;
  display: block;
 }
 .add-keyperson-dialog .upload__tip {
  font-size: 0.13rem;
  text-align: center;
  position: relative;
  z-index:10;
  top: -0.7rem;
 }
</style>

希望本文所述对大家vue.js程序设计有所帮助。