vue之原生上传图片并压缩图片大小(1)

vue之上传图片并压缩图片大小

vue之上传图片并压缩图片大小

这里使用的是 compressorjs , 安装 npm i compressorjs

注意:这个插件是利用canvas对图片进行重绘,如果压缩太过的话,会导致一定程度上的图片失真。

compressorjs官网
在这里插入图片描述
主要代码如下:

 <div class="van-uploader__upload">
     <i class="van-icon van-icon-photograph van-uploader__upload-icon"></i>
     <input type="file" multiple  accept="image/*" @change="handleImgUpload($event, item)"/>
 </div>
 
<style lang="scss">
.van-uploader__upload {
    display: none;
 }
</style>  
<script>
import Compressor from 'compressorjs';

export default {
 methods: {
  async handleImgUpload(e, item) {
      if (!e.target.files || !e.target.files.length) {
        return
      }
      const files = e.target.files
      if (files.length > 9) {
        this.$toast('一次最多上传9张,请分批次上传!')
        e.target.value = ''
        return
      }
      
      $loading.show()
      
      files.forEach(async (file, index) => {
        if (!file.name || !file.type.includes('image/')) {
          this.$toast('上传失败,只能上传照片!')
          // 上传完成
          if (index === files.length - 1) {
            //清空上传控件的值,防止不能重复上传
            e.target.value = ''
            $loading.hide()
          }
          return //forEach里的return相当于continue
        }
        if (file.size > 1024 * 1024 * 10) {
          this.$toast('文件太大,不能超过10M!')
          // 上传完成
          if (index === files.length - 1) {
            //清空上传控件的值,防止不能重复上传
            e.target.value = ''
            $loading.hide()
          }
          return
        }
        
        try {
          let formData = new FormData()
          // 大于512k则先压缩
          if (file.size > 512 * 1024) {
            const compressorFile = await this.compressor(file)
            formData.append('file', compressorFile, compressorFile.name)
          } else {
            formData.append('file', file, file.name)
          }

          const res = await imgUpload(formData)

          if (res.code === 0 && res.item) {
            item.answer.push({
              url: res.item,
            })
          } else {
            this.$toast('上传失败,请稍后重试!')
          }
        } catch (error) {
          this.$toast('上传失败,请稍后重试!')
          console.error(error)
        }
        
        // 上传完成
        if (index === files.length - 1) {
          //清空上传控件的值,防止不能重复上传
          e.target.value = ''
          $loading.hide()
        }
      })
    },
    // 压缩
    async compressor(file) {
      return new Promise(resolve => {
        new Compressor(file, {
          quality: 0.2,
          success: resolve,
          error(err) {
            console.log(err.message)
          },
        })
      })
    },
 } 
} 
</script>

代码片段如下:

<template>
  <div>
    <div class="scroll-wrapper" v-if="taskInfo">
      <template v-if="taskInfo.fileUrls && taskInfo.fileUrls.length">
        <div
          class="ml63 flex-center mt10 fs14"
          v-for="(item, idx) in taskInfo.fileUrls"
          :key="idx"
        >
          <div class="icon-file mr12">
            <img src="@/assets/img/icon-file@2x.png" alt="" />
          </div>
          <div class="task-file mw25 ellipse">{{ item.fileName }}</div>
          <div class="btn flex-center-center ml40">
            <a :href="item.fileUrl">预览</a>
          </div>
          <div class="btn flex-center-center ml32">
            <a :href="item.fileUrl">下载</a>
          </div>
        </div>
      </template>

      <div class="task-detail">
        <div class="task-caption" v-for="(item, idx) in questions" :key="idx">
          <!-- 图片上传 -->
          <div class="flex mt20" v-if="item.questionType === 4">
            <div  class="van-uploader__wrapper"  :class="{ 'task-img': isDisabled }">
              <div  class="van-uploader__preview"  v-for="(img, imgIdx) in item.answer"  :key="imgIdx">
                <div  class="van-image van-uploader__preview-image"  @click="handlePreview(item.answer, imgIdx)">
                  <img  class="van-image__img"  :src="img.url"  style="object-fit: cover"/>
                </div>
                <div  v-if="!isDisabled"  class="van-uploader__preview-delete"  @click="item.answer.splice(imgIdx, 1)">
                  <i  class="van-icon van-icon-cross van-uploader__preview-delete-icon"></i>
                </div>
              </div>

              <div class="van-uploader__upload" v-if="!isDisabled">
                <i  class="van-icon van-icon-photograph van-uploader__upload-icon"></i>
                <input  type="file"  multiple  accept="image/*"  @change="handleImgUpload($event, item)"  class="van-uploader__input"/>
              </div>
            </div>
          </div>

          <!-- 附件上传 -->
          <div class="mt20 file-upload" v-if="item.questionType === 5">
            <div  class="flex file-item"  v-for="(file, fileIdx) in item.answer"  :key="fileIdx">
              <div class="file-left">
                <div class="icon-file mr12">
                  <img src="@/assets/img/icon-file@2x.png" alt="" class="" />
                </div>
                <div class="task-file file-name ellipse">
                  {{ file.fileName }}
                </div>
              </div>

              <div class="task-file ml40" v-if="!isDisabled">
                <span @click="removeFile(item, fileIdx)">删除</span>
              </div>
              <div class="ml20 task-file flex-center-center" v-else>
                <div class="btn flex-center-center">
                  <a :href="file.fileUrl">预览</a>
                </div>
                <div class="btn flex-center-center ml32">
                  <a :href="file.fileUrl">下载</a>
                </div>
              </div>
            </div>
            
            <van-button  color="#4646E6"  class="mt40 ml40"  @click="handleFileClick('file' + idx)"  :disabled="isDisabled">
              <div class="flex-center fs14">
                <input  :id="'file' + idx"  type="file"  style="display: none"  @change="handleFileUpload($event, item)"/>
                <div class="file-icon mr12">
                  <img src="@/assets/img/icon-file_upload@2x.png" />
                </div>
                附件上传
              </div>
            </van-button>
          </div>

        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { getTaskDetail, imgUpload, fileUpload, userExecute } from '@/api/myTask'
import { ImagePreview } from 'vant'
import Compressor from 'compressorjs'

const fileExtensions = ['xlsx', 'xls', 'docx', 'doc', 'pdf']

export default {
  name: 'index',
  components: {},
  props: {},
  data() {
    return {
      id: this.$route.params.id,
      from: this.$route.query.from,
      shareAccount: this.$route.query.shareAccount,
      taskInfo: null,
      questions: [],
      currentItem: null,
      imgList: [],
    }
  },
  mounted() {
    this.getTaskDetail(this.id)
  },
  methods: {
    async getTaskDetail(id) {
      try {
        $loading.show()
        const data = { id }
        if (this.from === 'behalfTask') {
          data.userAccountId = this.shareAccount
        }
        const res = await getTaskDetail(data)
        $loading.hide()
        if (res.code === 0) {
          this.taskInfo = res.item
          this.initQuestions(this.taskInfo.taskItem)
        }
      } catch (error) {
        $loading.hide()
        console.error(error)
      }
    },
    initQuestions(taskItem) {
      for (const item of taskItem) {
        let question = {}
        question.itemId = item.itemId
        question.title = item.title
        question.questionDescribe = (item.questionDescribe && '(' + item.questionDescribe + ')') || ''
        question.questionType = item.questionType
        question.required = item.required
        question.options = item.itemContent
        // 处理问题答案
        switch (item.questionType) {
          // 图片上传
          case 4:
            if (item.itemExecute && item.itemExecute.taskItemExecute) {
              question.answer = item.itemExecute.taskItemExecute
                .split(',')
                .map(img => {
                  return { url: img }
                })
            } else {
              question.answer = []
            }
            break
          // 附件上传
          case 5:
            if (item.itemExecute && item.itemExecute.taskItemExecute) {
              question.answer = item.itemExecute.taskItemExecute
                .split(',')
                .map(file => {
                  if (file.split('&').length === 2) {
                    return {
                      fileUrl: file.split('&')[0],
                      fileName: file.split('&')[1],
                    }
                  }
                  return { fileUrl: '', fileName: '' }
                })
            } else {
              question.answer = []
            }
            break
        }
        this.questions.push(question)
      }
    },
    // 点击事件
    handleFileClick(el) {
      document.getElementById(el).click()
    },
    // 附件上传
    async handleFileUpload(e, item) {
      if (!e.target.files || !e.target.files.length) {
        return
      }
      if (!e.target.files[0].name || e.target.files[0].name.split('.').length < 2) {
        this.$toast('无效文件!')
        return
      }
      if (!fileExtensions.includes(e.target.files[0].name.split('.')[1].toLowerCase())) {
        this.$toast.fail('请选择附件文件类型')
        return
      }
      if (e.target.files[0].size > 1024 * 1024 * 10) {
        this.$toast.fail('文件太大,不能超过10M!')
        return
      }
      try {
        const res = await fileUpload({ file: e.target.files[0] })
        // 清空上传控件的值,防止不能重复上传
        e.target.value = ''
        if (res.code === 0) {
          item.answer.push({
            fileName: res.item.fileName,
            fileUrl: res.item.fileUrl,
          })
        }
      } catch (error) {
        e.target.value = ''
        console.error(error)
      }
    },
    // 图片上传
    async handleImgUpload(e, item) {
      if (!e.target.files || !e.target.files.length) {
        return
      }
      const files = e.target.files
      if (files.length > 5) {
        this.$toast('一次最多上传5张,请分批次上传!')
        e.target.value = ''
        return
      }

      $loading.show()

      files.forEach(async (file, index) => {
        if (!file.name || !file.type.includes('image/')) {
          this.$toast('上传失败,只能上传照片!')
          // 上传完成
          if (index === files.length - 1) {
            //清空上传控件的值,防止不能重复上传
            e.target.value = ''
            $loading.hide()
          }
          return //forEach 里的 return 相当于 continue
        }
        if (file.size > 1024 * 1024 * 10) {
          this.$toast('文件太大,不能超过10M!')
          // 上传完成
          if (index === files.length - 1) {
            //清空上传控件的值,防止不能重复上传
            e.target.value = ''
            $loading.hide()
          }
          return
        }
        try {
          let formData = new FormData()
          // 大于512k则先压缩
          if (file.size > 512 * 1024) {
            const compressorFile = await this.compressor(file)
            formData.append('file', compressorFile, compressorFile.name)
          } else {
            formData.append('file', file, file.name)
          }

          const res = await imgUpload(formData)

          if (res.code === 0 && res.item) {
            // 给item 添加图片路径
            item.answer.push({
              url: res.item,
            })
          } else {
            this.$toast('上传失败,请稍后重试!')
          }
        } catch (error) {
          this.$toast('上传失败,请稍后重试!')
          console.error(error)
        }
        // 上传完成
        if (index === files.length - 1) {
          //清空上传控件的值,防止不能重复上传
          e.target.value = ''
          $loading.hide()
        }
      })
    },

    // 图片压缩
    async compressor(file) {
      return new Promise(resolve => {
        new Compressor(file, {
          quality: 0.2,
          success: resolve,
          error(err) {
            console.log(err.message)
          },
        })
      })
    },

    // 图片预览
    handlePreview(imgList, startPosition) {
      ImagePreview(
        imgList.map(item => item.url),
        startPosition
      )
    },
    // 附件删除
    removeFile(ques, fileIdx) {
      this.$dialog
        .confirm({ message: `是否删除附件“${ques.answer[fileIdx].fileName}` })
        .then(() => {
          ques.answer.splice(fileIdx, 1)
        })
        .catch(() => {})
    },
  },
  computed: {
    isDisabled() {
      return (
        // 直接进入此页面的只允许查看
        !this.from ||
        //从执行记录进来的只允许查看
        this.from === 'executeRecord' ||
        //代执行却没有代执行人的ID不允许执行
        (this.from === 'behalfTask' && !this.shareAccount) ||
        //已执行任务不允许再执行
        this.taskInfo.execStatus === 1 ||
        //不允许超期执行且已超期则不允许执行
        (!this.taskInfo.allowOverDue && !!this.taskInfo.overdueFlag)
      )
    },
  },
}
</script>

上传代码部分感谢龙哥的帮忙和指导;

其中接口调接口写法

import request from '@/utils/request'
import store from '@/store'

function addParams(params) {
  if (!params.userAccountId) {
    params.userAccountId = store.getters.userAccountID
  }
}

// 图片上传
export function imgUpload(data = {}) {
  // addParams(data)
  // let postBody = new FormData()
  // for (const key in data) {
  //   postBody.append(key, data[key])
  // }
  return request({
    url: '/api/image/upload',
    method: 'post',
    data
  })
}

// 附件上传
export function fileUpload(data = {}) {
  addParams(data)
  let postBody = new FormData()
  for (const key in data) {
    postBody.append(key, data[key])
  }
  return request({
    url: '/api/file/upload',
    method: 'post',
    data: postBody
  })
}

注意点:

选择图片时,需要清空一下这个值,防止同一张图片不让多次选择上传;

e.target.value = ''

其他写法:

<template>
  <div class="ele-upload-styl">
    <!-- <el-upload
      action=""
      :headers="uploadProps.headers"
      :show-file-list="false"
      :http-request="fnUploadRequest"
      :on-success="handleSuccess"
      :before-upload="handleUpload"
      accept=".png,.jpg,.jpeg,.gif,.webp"
      multiple
      :limit="5"
      :on-exceed="handleExceed"
      ref="upload"
    >
      <div class="img-cont pr">
        <img slot="trigger" class="img-icon" src="@/assets/img/icon-img-upload.png" alt="">
        <span slot="tip" class="img-text">图片</span>
      </div>
    </el-upload> -->
    
    <-- 原生写法-->
    <label for="myFile">
      <input
        type="file"
        multiple
        accept="image/*"
        id="myFile"
        @change="handleImgUpload($event)"
        style="display: none"
      />
      <div class="img-cont pr">
        <img
          slot="trigger"
          class="img-icon"
          src="@/assets/img/icon-img-upload.png"
          alt=""
        />
        <span slot="tip" class="img-text">图片</span>
      </div>
    </label>
  </div>
</template>

<script>
import {
  getAccessToken,
  getRefreshToken,
  getAccessTokenTTL
} from '@/utils/auth'
import { uploadOSS } from '@/utils/ossImage'

export default {
  name: 'imgUpload',
  components: {},
  props: {},
  computed: {
    userAccountID() {
      return this.$store.state.user.userAccountID
    },
    uploadProps() {
      return {
        // action: `${process.env.VUE_APP_BASE_API}/api/image/upload`,
        headers: {
          // 接口可能要带token: "",
          Authorization: getAccessToken()
        },
        data: {}
      }
    }
  },
  data() {
    return {}
  },
  methods: {
    // handleExceed(file, fileList) {
    //   // console.log(file, fileList);
    //   this.$message.error("上传失败,限制上传数量10张图片以内!");
    // },
    // beforeUpload_u(file, fileList) {
    //   // console.log(file, fileList);
    //   var testmsg = file.name.substring(file.name.lastIndexOf(".") + 1);
    //   const extension =
    //     testmsg === "png" ||
    //     testmsg === "jpg" ||
    //     testmsg === "jpeg" ||
    //     testmsg === "gif" ||
    //     testmsg === "webp";
    //   const isLimit10M = file.size / 1024 / 1024 < 10;
    //   var bool = false;
    //   if (extension && isLimit10M) {
    //     bool = true;
    //   } else {
    //     bool = false;
    //   }
    //   if (!extension) {
    //     this.$message.error("请上传图片格式文件!");
    //     return bool;
    //   }
    //   if (!isLimit10M) {
    //     this.$message.error("上传失败,不能超过10M!");
    //     return bool;
    //   }
    //   return bool;
    // },
    // handleSuccess(res) {
    //   // console.log(res);
    //   if (res.code == 0) {
    //     this.$emit("imgData", res.item);
    //     this.$message.success("上传图片成功!");
    //   } else {
    //     this.$message.error("上传图片失败!");
    //   }
    // },
    // handleError(err) {
    //   this.$message.error("上传图片失败!");
    // },

    // 上传图片判断
    handleUpload(file) {
      // console.log(file);
      var testmsg = file.name.substring(file.name.lastIndexOf('.') + 1)
      const extension =
        testmsg.toLowerCase() === 'png' ||
        testmsg.toLowerCase() === 'jpg' ||
        testmsg.toLowerCase() === 'jpeg' ||
        testmsg.toLowerCase() === 'gif' ||
        testmsg.toLowerCase() === 'webp'

      const isLimit10M = file.size / 1024 / 1024 < 10
      var bool = false
      if (extension && isLimit10M) {
        bool = true
      } else {
        bool = false
      }
      if (!extension) {
        this.$message.error('请上传图片格式文件!')
        return bool
      }
      if (!isLimit10M) {
        this.$message.error('文件太大,单个文件不能超过10M! ')
        return bool
      }
      return bool
    },
    handleExceed(files, fileList) {
      // console.log(files, fileList);
      this.$message.warning(` 一次最多上传5张,请分批次上传! `)
    },
    // 上传图片
    async fnUploadRequest(options) {
      // console.log(options);
      try {
        this.$loading.show()
        // console.log(options);
        let file = options.file // 拿到 file
        let res = await uploadOSS(file)
        // console.log(res);
        // 返回的就是图片地址
        this.$emit('imgData', res)
        this.$loading.hide()
      } catch (e) {
        this.$loading.hide()
        this.$message.error('上传图片失败!请重新上传')
      }
    },
    //图片上传成功回调
    handleSuccess(res) {
      // console.log(res);
      this.$refs.upload.clearFiles() //清空选择列表
      if (res) {
        this.$emit('imgData', res)
      }
    },
    
    // 原生的方法 触发调接口,其他操作自行研究
    handleImgUpload(e) {
      console.log(e.target.files)
      e.target.files.forEach(async (file) => {
        console.log(file)
        try {
          this.$loading.show()
          let res = await uploadOSS(file)
          // console.log(res);
          // 返回的就是图片地址
          this.$emit('imgData', res)
          this.$loading.hide()
          }  catch (e) {
          this.$loading.hide()
          this.$message.error('上传图片失败!请重新上传')
        }
      })
      e.target.value = ''
    }
  }
}
</script>
<style  lang="scss" scoped>
::v-deep .el-upload,
::v-deep .el-upload--picture-card {
  // width: 50px;
  height: 24px;
  border: none;
  line-height: 0;
  display: block;
  background: #f5f6fb;
}
::v-deep .el-upload {
  width: 50px;
}
.img-cont {
  width: 50px;
  height: 24px;
  background: #f5f6fb;
  .img-icon {
    color: #ccc;
  }
  .img-text {
    font-size: 12px;
    height: 24px;
    color: #000;
    margin-left: 3px;
  }
}
</style>

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值