vue+vant 利用FormData上传图片(单张or多张)第二版

介绍:vant版本2.3.3
流程:input选取file=>append到FormData中=>提交后台。
利用FormData上传,这个流程无论换什么ui框架,或者自己写都走得通,亲测有效。(自己手写的上传就不拿出来分享了,主要是太乱,自己都看半天)
效果:
vue+vant 利用FormData上传图片(单张or多张)第二版_第1张图片

1.未封装afterRead版

代码如下:

html

//v-if中的条件不重要
<p class="txt mb10" v-if="$route.query.clockStage%4 != 0">购药发票</p>
<p :class="['img','mb15',$route.query.clockId&&detail.status!=2&&detail.invoiceAud!=2?'noLook':'']">
 <van-uploader
 //只是禁用,还是显示上传按钮,使用noLook解决
  :disabled='$route.query.clockId&&detail.status!=1&&detail.invoiceAud!=2?true:false' 
  :max-count="5"
  //右上角删除
  :deletable='$route.query.clockId&&detail.invoiceAud!=2?false:true' 
  v-model="form2.invoiceUrl"
  :after-read="afterRead2"
  v-if="$route.query.clockStage%4 != 0"
  />
  <span class="show colore5" v-if="detail.invoiceAud==2">{{detail.invoiceRemarks}}</span>
</p>

<p class="txt mb10" v-if="$route.query.clockStage%4 != 0">购药证明</p>
  <p :class="['img','mb15',$route.query.clockId&&detail.status!=2&&detail.invoiceProveAud!=2?'noLook':'']">
  <van-uploader
  :disabled='$route.query.clockId&&detail.status!=1&&detail.invoiceProveAud!=2?true:false'
  :max-count="5"
  :deletable='$route.query.clockId&&detail.invoiceProveAud!=2?false:true'
  v-model="form2.invoiceProveUrl"
  :after-read="afterRead8"
  v-if="$route.query.clockStage%4 != 0"
  />
  <span class="show colore5" v-if="detail.invoiceProveAud==2">{{detail.invoiceProveRemarks}}</span>
</p>

<van-button type="primary" class="w100 submit ml20 mr20 mt30 mb10" @click="submit">{{detail.status==2?'重新打卡':'打卡'}}</van-button>

js

data(){
	return {
		form2:{
	        invoiceUrl:[],
	        invoiceProveUrl:[],
	        detail:{}
      },
	}
},
created () {
    const {clockId,clockStage} = this.$route.query;
    if(clockId) this.getDetail(clockId);
  },
methods: {
	getDetail(id){ //用于回显默认数据
      axios.get(this.$my.api+"/voluntee/selectClockInfo?id="+id,)
      .then((res)=>{
        if (res.data) {
          if (res.data.code == 200) {
            let val = res.data.data
            this.detail =val
            let setVal = (arr)=>{
              let newArr = []
              arr = arr?arr.split(','):[]
              arr.map((item)=>{
                if(item){
                  newArr.push({url:item}) 
                }
              })
              return newArr
            }
            this.form2 = {
              ...this.form2,
              invoiceUrl: setVal(val.invoiceUrl),
              invoiceProveUrl:setVal(val.invoiceProveUrl),
            }
          } else {
            this.$toast(res.data.message);
          }
        }
      })
      .catch((error) => {});
    },
	//上传发票
	afterRead2(file){
	  that.$uploadImg(this.$my.api+'/wechat/upload',file)
	  .then((res)=>{
	    let arr = [...this.form2.invoiceUrl]
	    arr.push({url:res})
	    this.form2.invoiceUrl = arr.filter((item)=>!('file' in item))
	    this.$toast.loading({
			forbidClick:true,
			overlay:true,
			duration:1000,
			message:'上传完成'
		})
	  })
	},
	//购药证明
	afterRead8(file){
	  this.$uploadImg(this.$my.api+'/wechat/upload',file)
	  .then((res)=>{
	    let arr = [...this.form2.invoiceProveUrl]
	    arr.push({url:res})
	    this.form2.invoiceProveUrl = arr.filter((item)=>!('file' in item))
	    this.$toast.loading({
			forbidClick:true,
			overlay:true,
			duration:1000,
			message:'上传完成'
		})
	  })
	},
	submit(){ 
      let that = this
      const {clockStage ,cardId} = this.$route.query;
      let rules = {
          invoiceUrl:'购药发票',
          invoiceProveUrl:'购药证明',
        }

      if(Object.keys(rules).find(item=>this.form2[item] == '')){
        this.$toast(rules[Object.keys(rules).find(item=>this.form2[item] == '')]+'不能为空')
        return false
      }

      let getVal = (arr)=>{
        let newArr = []
        arr.map((item)=>{
        newArr.push(item.url) 
        })
        return newArr.join(',')  
      }
      let val= {
        //id:this.detail.status ==2?this.detail.id:'',
        //userId:JSON.parse(localStorage.getItem('volunteerInfo')).id, 
        //userName:JSON.parse(localStorage.getItem('volunteerInfo')).name,
   
        invoiceUrl:getVal(this.form2.invoiceUrl),
        invoiceProveUrl:getVal(this.form2.invoiceProveUrl),
      }
      
      let url = ["/voluntee/saveOneClock","/voluntee/saveTwoClock","/voluntee/saveTwoClock","/voluntee/saveFourClock"]
      
      this.$toast.loading({
        duration:0,
        mask: true,
        message: '加载中...'
      });
      axios.post(this.$my.api+url[(clockStage-1)%4], val)
      .then((res)=>{
        if (res.data) {
          if (res.data.code == 200) {
            this.$router.go(-1)
            this.$toast.loading({
              type:'success',
              mask: true,
              message: res.data.message
            });
            setTimeout(() => {  
               this.$toast.clear()
            }, 1000);
          } else {
            this.$toast(res.data.message);
          }
        }
      })
      .catch((error) => {});
    },
}

上传方法

//同事封装的,我copy的
import axios from 'axios'
import { Toast } from 'vant'

const compress = (fileObj)=>{
	return new Promise((rej,err)=>{
		// max 500 * 320
        const maxHeight = 2000
        const maxWidth = 1200
        let img = new Image()
        img.src = fileObj
        img.onload = () => {
          const originHeight = img.height
          const originWidth = img.width
          let compressedWidth = img.height
          let compressedHeight = img.width
          if ((originWidth > maxWidth) && (originHeight > maxHeight)) {
            // 更宽更高,
            if ((originHeight / originWidth) > (maxHeight / maxWidth)) {
              // 更加严重的高窄型,确定最大高,压缩宽度
              compressedHeight = maxHeight
              compressedWidth = maxHeight * (originWidth / originHeight)
            } else {
              //更加严重的矮宽型, 确定最大宽,压缩高度
              compressedWidth = maxWidth
              compressedHeight = maxWidth * (originHeight / originWidth)
            }
          } else if (originWidth > maxWidth && originHeight <= maxHeight) {
            // 更宽,但比较矮,以maxWidth作为基准
            compressedWidth = maxWidth
            compressedHeight = maxWidth * (originHeight / originWidth)
          } else if (originWidth <= maxWidth && originHeight > maxHeight) {
            // 比较窄,但很高,取maxHight为基准
            compressedHeight = maxHeight
            compressedWidth = maxHeight * (originWidth / originHeight)
          } else {
            // 符合宽高限制,不做压缩
          }
          let compressedCanvas = document.createElement("canvas")
          let context = compressedCanvas.getContext("2d")
          compressedCanvas.height = compressedHeight
          compressedCanvas.width = compressedWidth
          context.clearRect(0, 0, compressedWidth, compressedHeight)
          context.drawImage(img, 0, 0, compressedWidth, compressedHeight)
          let base64_img = compressedCanvas.toDataURL('image/jpeg')
          const blobBin = atob(base64_img.split(',')[1]);
          let data = [];
          for(var i = 0; i < blobBin.length; i++) {
              data.push(blobBin.charCodeAt(i));
          }
          let file = new Blob([new Uint8Array(data)], {type: 'image/png'});
          // 上传file 至服务器
          //this.uploadFile(file)
          rej(file)
        }
	})
}
export async function postHttp(url,data ={}){
  Toast.loading({
    forbidClick:true,
    overlay:true,
    duration:0,
    message:'上传当中....'
  })
  //这个地方,如果多选请自行修改,参考第一版
  const device = [data]
  let formData = new FormData();
  let a = new FileReader()
   device.map((item)=>{
    formData.append('files', item.file ,item.file.name);
  })
  //压缩
  //let formData = new FormData();
  //let file = await compress(data.content)
  //formData.append('files',file);

  return new  Promise((resolve,reject)=>{
    axios.post(url, formData,  {headers:{'Content-Type':'multipart/form-data'}})
      .then(res=>{
        resolve(res.data)
      },(err) =>{
        reject(err)
        Toast.loading({
          forbidClick:true,
          overlay:true,
          duration:1000,
          message:'上传失败,请重新上传'
        })
      })
  })
}

css

.img >>> .van-uploader__preview{ margin: 0 .2rem .1rem 0;position: relative;}
.noLook >>> .van-uploader__upload{display: none;}//隐藏上传按钮

2.封装afterRead版

html

<div class="flex justs alic lh60">
	<span>上传身份证:</span>
	<span class="colorf3 flex alic" @click="isShowHelp = true;helpType = 'card'"><van-icon name="question" color="#F3665E" class="mr5"/>帮助说明</span>
</div>
<div class="flex justs">
	<p :class="['cardImg','boxImg','w100',form.cardFrontUrl.length>0?'flexImg':'',(detail.status==2&&detail.isOld==1) || detail.cardFrontAud==2 || ($route.query.giveId?false:true)?'':'noLook']" @click="activec = 'cardFrontUrl'">
		<!-- capture='camera' -->
		<van-uploader
		:max-count="2"
		:deletable='(detail.status==2&&detail.isOld==1) || detail.cardFrontAud==2 || ($route.query.giveId?false:true)?true:false'
		v-model="form.cardFrontUrl"
		:after-read="afterRead"
		upload-text='身份证'
		image-fit='fill'
		/>
		<!-- :disabled='(detail.status==2&&detail.isOld==1) || detail.cardFrontAud==2?false:true' -->
		<span class="show colore5 remark" v-if="detail.status==2 && detail.cardFrontAud==2">{{detail.cardFrontRemarks}}</span>
	</p>
</div>

<div class="flex justs alic lh60">
	<span>上传发票:<van-button type="primary" v-if="isVolun&&invoiceObj.flag == 'Y'&&detail.status!=1&&detail.status!=0" size="small" @click="showInvoice = true">已上传,选择发票</van-button></span>
	<span class="colorf3 flex alic" @click="isShowHelp = true;helpType = 'invoice'"><van-icon name="question" color="#F3665E" class="mr5"/>帮助说明</span>
</div>
<div class="flex justs">
	<p :class="['invoiceImg','boxImg' ,'w100',(detail.status==2&&detail.isOld==1) || detail.invoiceOneAud==2 || ($route.query.giveId?false:true)?'':'noLook']" @click="activec = 'invoiceOneUrl'">
		<van-uploader
		:max-count="9"
		:deletable='(detail.status==2&&detail.isOld==1) || detail.invoiceOneAud==2 || ($route.query.giveId?false:true)?true:false'
		v-model="form.invoiceOneUrl"
		:after-read="afterRead"
		upload-text='购药发票'
		image-fit='fill'
		/>
		<!-- :disabled='(detail.status==2&&detail.isOld==1) || detail.invoiceOneAud!=2?false:true' -->
		<span class="show colore5" v-if="detail.status==2 && detail.invoiceOneAud==2">{{detail.invoiceOneRemarks}}</span>
	</p>
</div>

js

//data数据
form:{
	cardFrontUrl:[],
	invoiceOneUrl:[],
},
detail:{},
activec:'',

//method
afterRead(file){
	this.$upload.uploadImg(this.$config.api+'/wechat/upload',file)
	.then((res)=>{
		if(res){
			let arr = [...this.form[this.activec]]
			arr.push({url:res,isImage: true})
			this.form[this.activec] = arr.filter((item)=>!('file' in item))
			this.$toast.loading({
				forbidClick:true,
				overlay:true,
				duration:1000,
				message:'上传完成'
			})
		}
	},err=>{
		this.form[this.activec].pop() //处理500情况下,删除组件自动选择图片
	})
},

其他代码,和上面一样。只是把多个afterRead写到一个里面,节省代码。

你可能感兴趣的:(Vant,vant,上传,vue)