• vue图片上传组件


    1、正常上传

    <template>
      <div class="upload-wrapper">
        <div v-if="!imgUrl" class="noneData">
          <div @click="openLocals">
            <img src="./imgs/icon_jh.png" alt="">
            <div>上传图片</div>
          </div>
          <form :id="fileName+'Form'" enctype="multipart/form-data" style="display:none;">
            <input ref="pathClear" type="file"  accept="image/*" :name="fileName" @change="fileChanged"/>
          </form>
        </div>
        <div v-else class="havaData">
          <img :src="imgUrl" alt="" @click="actImg">
        </div>
      </div>
    </template>
    <script>
    import $ from 'jquery';
    import { Indicator, Toast } from 'mint-ui';
    import { webPostObject } from './ossUpload/index.js';
    export default {
      data() {
        return {
        };
      },
      props: {
        // file控件名称
        fileName: {
          type: String,
          required: true
        },
        // 图片地址
        imgUrl: {
          type: String,
          default: '',
          required: true
        },
      },
      methods: {
        // 点击图片
        actImg() {
          console.log('点击图片');
        },
        // 删除图片
        removePackage() {
          let _self = this;
          _self.$emit('removeImg');
        },
        // 上传图片
        openLocals() {
          $(`input[type='file'][name='${this.fileName}']`).click();
        },
        fileChanged() {
          this.uploadImg();
        },
        uploadImg() {
          let _self = this;
          let fileElement = $(`input[type='file'][name='${_self.fileName}']`);
          let filename = fileElement.val();
          let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
          if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') {
            Toast({
              message: '仅支持.jpg、.png、.jpeg、.bmp的图片格式',
              position: 'bottom',
              duration: 2000
            });
            return false;
          }
          let file = fileElement[0].files[0];
          let imgSize = Math.ceil(file.size / 1024 / 1024);
          if (imgSize > 20) {
            Toast({
              message: '文件不能大于20MB,重新选择文件',
              position: 'bottom',
              duration: 2000
            });
            _self.$refs.pathClear.value = '';
            return false;
          }
          Indicator.open('图片正在上传中...');
          // 服务器上传
          // let formdata1 = new FormData();
          // formdata1.append('file', file, file.name);
          // let config = {
          //   headers: { 'Content-Type': 'multipart/form-data' }
          // };
          // axios.post(`${process.env.UPLOAD_HOST}`, formdata1, config).then((res) => {
          //   console.log(res);
          //   let data = res.data;
          //   Indicator.close();
          //   if (data) {
          //     _self.$emit('uploadSuccess', data[0]);
          //   }
          // }).catch(() => {
          //   Indicator.close();
          //   Toast({
          //     message: '图片上传失败',
          //     position: 'bottom',
          //     duration: 2000
          //   });
          // });
          // oss web直传
          webPostObject(file, file.name).then(data => {
            console.log('oss web直传', data);
            Indicator.close();
            _self.$emit('uploadSuccess', data);
          }).catch(() => {
            Indicator.close();
            Toast({
              message: '图片上传失败',
              position: 'bottom',
              duration: 2000
            });
          });
        },
      },
    };
    </script>
    <style lang="less" scoped>
    .upload-wrapper{
      height: 100%;
    }
    .noneData,.havaData{
      position: relative;
      height: 100%;
    }
    .noneData{
      background-color: #eeeeee;
      color: #999999;
      font-size: 12px;
      text-align: center;
      padding-top: 15px;
      img{
         26px;
        height: 26px;
      }
    }
    .havaData{
      img{
         100%;
        height: 100%;
      }
    }
    </style>

    2、压缩图片上传

    <template>
      <div class="upload-wrapper">
        <div v-if="!imgUrl" class="noneData">
          <div class="uploadImg" @click="openLocals">
          </div>
          <form :id="fileName+'Form'" enctype="multipart/form-data" style="display:none;">
            <input ref="pathClear" type="file"  accept="image/*" :name="fileName" @change="fileChanged"/>
          </form>
        </div>
        <div v-else class="havaData">
         <div class="havaDataimg">
            <div class="img_wap">
              <img :src="imgUrl" alt="" @click.stop="bigPicture">
            </div>
            <div class="remove" @click.stop="removePackage"></div>
         </div>
        </div>
        <div class="maxImg" @click="minImg" v-if="maxImg">
          <img :src="imgUrl" alt="">
        </div>
      </div>
    </template>
    <script>
    import $ from 'jquery';
    import { Indicator, Toast } from 'mint-ui';
    import axios from 'axios';
    export default {
      data() {
        return {
          maxImg: false,
          xhr: null,
          ot: null,
          oloaded: null,
        };
      },
      props: {
        // file控件名称
        fileName: {
          type: String,
          required: true
        },
        // 图片地址
        imgUrl: {
          type: String,
          default: '',
          required: true
        },
        // 图片地址
        isMaxIMg: {
          type: String,
          default: '',
          required: true
        },
      },
      methods: {
        // 查看大图
        bigPicture() {
          console.log(this.isMaxIMg);
          if (this.isMaxIMg === '0') {
            return false;
          }
          this.maxImg = true;
        },
        // 恢复小图
        minImg() {
          this.maxImg = false;
        },
        // 删除图片
        removePackage() {
          let _self = this;
          _self.$emit('removeImg');
        },
        // 上传图片
        openLocals() {
          $(`input[type='file'][name='${this.fileName}']`).click();
        },
        fileChanged() {
          this.UpladFile();
        },
        // 三个参数
        // file:一个是文件(类型是图片格式),
        // w:一个是文件压缩的后宽度,宽度越小,字节越小
        // objDiv:一个是容器或者回调函数
        // photoCompress()
        photoCompress(file, w, objDiv) {
          let that = this;
          let ready = new FileReader();
          // 开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.
          ready.readAsDataURL(file);
          ready.onload = function() {
            let re = this.result;
            that.canvasDataURL(re, w, objDiv);
          };
        },
        canvasDataURL(path, obj, callback) {
          let img = new Image();
          img.src = path;
          img.onload = function() {
            let that = this;
            // 默认按比例压缩
            let w = that.width;
            let h = that.height;
            let scale = w / h;
            w = obj.width || w;
            h = obj.height || (w / scale);
            let quality = 0.7;  // 默认图片质量为0.7
            // 生成canvas
            let canvas = document.createElement('canvas');
            let ctx = canvas.getContext('2d');
            // 创建属性节点
            let anw = document.createAttribute('width');
            anw.nodeValue = w;
            let anh = document.createAttribute('height');
            anh.nodeValue = h;
            canvas.setAttributeNode(anw);
            canvas.setAttributeNode(anh);
            ctx.drawImage(that, 0, 0, w, h);
            // 图像质量
            if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
              quality = obj.quality;
            }
            // quality值越小,所绘制出的图像越模糊
            let base64 = canvas.toDataURL('image/jpeg', quality);
            // 回调函数返回base64的值
            callback(base64);
          };
        },
        /**
         * 将以base64的图片url数据转换为Blob
         * @param urlData
         *            用url方式表示的base64图片数据
         */
        convertBase64UrlToBlob(urlData) {
          let arr = urlData.split(',');
          let mime = arr[0].match(/:(.*?);/)[1];
          let bstr = atob(arr[1]);
          let n = bstr.length;
          let u8arr = new Uint8Array(n);
          while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
          }
          return new Blob([u8arr], { type: mime });
        },
        // 上传文件方法
        UpladFile() {
          let that = this;
          let fileElement = $(`input[type='file'][name='${that.fileName}']`);
          let filename = fileElement.val();
          let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
          if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') {
            Toast({
              message: '仅支持.jpg、.png、.jpeg、.bmp的图片格式',
              position: 'bottom',
              duration: 2000
            });
            return false;
          }
          let fileObj = fileElement[0].files[0];
          let form = new FormData(); // FormData 对象
          if (fileObj.size / 1024 > 1025) { // 大于1M,进行压缩上传
            that.photoCompress(fileObj, {
              quality: 0.2
            }, function(base64Codes) {
              let bl = that.convertBase64UrlToBlob(base64Codes);
              form.append('file', bl, 'file_' + Date.parse(new Date()) + '.jpg'); // 文件对象
              let config = {
                headers: { 'Content-Type': 'multipart/form-data' }
              };
              Indicator.open('图片正在上传中...');
              axios.post(`${process.env.UPLOAD_HOST}`, form, config).then((res) => {
                console.log(res);
                let data = res.data;
                Indicator.close();
                if (data) {
                  that.$emit('uploadSuccess', data[0]);
                }
              }).catch(() => {
                Indicator.close();
                Toast({
                  message: '图片过大上传失败',
                  position: 'bottom',
                  duration: 2000
                });
              });
            });
          } else { // 小于等于1M 原图上传
            Indicator.open('图片正在上传中...');
            form.append('file', fileObj); // 文件对象
            axios.post(`${process.env.UPLOAD_HOST}`, form).then((res) => {
              console.log(res);
              let data = res.data;
              Indicator.close();
              if (data) {
                that.$emit('uploadSuccess', data[0]);
              }
            }).catch(() => {
              Indicator.close();
              Toast({
                message: '图片过大上传失败',
                position: 'bottom',
                duration: 2000
              });
            });
          }
        },
      }
    };
    </script>
    
    <style lang="less" scoped>
    .upload-wrapper{
      position: relative;
      height: 172px;
    }
    .noneData,.havaData{
      height: 100%;
      padding: 15px 16vw;
      position: relative;
      display: flex;
      justify-content: center;
      align-items: center;
      .uploadImg{
         102px;
        height: 102px;
        background-size: 100% 100%;
        background-image: url(./imgs/xh_pfgy_upload.png);
      }
      .havaDataimg{
        position: relative;
         100%;
        height: 100%;
        border: 1px solid #eeeeec;
        overflow: hidden;
        .img_wap{
           100%;
          height: 0px;
          padding-bottom: 56%;
          position: relative;
          img{
             100%;
            position: absolute;
            top: -30%;
            left: 0px;
          }
        }
        .remove{
          position: absolute;
          top: 0;
          right: 0;
           18px;
          height: 18px;
          background: url('./imgs/icon_close.png') rgba(255, 255, 255, 0.8) center center no-repeat;
          background-size: cover;
          border-radius: 50%;
        }
      }
    }
    // 大图效果
    .maxImg{
      position: fixed;
      top: 0px;
      left: 0px;
      right: 0px;
      bottom: 0px;
      overflow: auto;
      background-color:rgba(0, 0, 0, 0.5);
      z-index: 100;
      padding: 20px;
      display: flex;
      justify-content: center;
      align-items: center;
      img{
        max- 100%;
        max-height: 100%;
      }
    }
    </style>

    3、转为base64上传

    <template>
      <div>
        <div style="padding:20px;">
          <!-- <div class="show">
            <div class="picture" :style="'backgroundImage:url('+headerImage+')'"></div>
          </div> -->
          <div class="havaDataimg">
             <div class="img_wap">
              <img  :src="headerImage"  alt="">
            </div>
            <div class="remove"></div>
          </div>
          <div style="margin-top:20px;">
            <input type="file" id="upload" accept="image/*" @change="upload">
            <label for="upload"></label>
          </div>
        </div>
      </div>
    </template>
    <script>
    import Exif from 'exif-js';
    import { Toast } from 'mint-ui';
    export default {
      data() {
        return {
          headerImage: '',
          picValue: ''
        };
      },
      methods: {
        upload(e) {
          let files = e.target.files || e.dataTransfer.files;
          if (!files.length) return;
          this.picValue = files[0];
          let filename = this.picValue.name;
          let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
          if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') {
            Toast({
              message: '仅支持.jpg、.png、.jpeg、.bmp的图片格式',
              position: 'bottom',
              duration: 2000
            });
            return false;
          }
          this.imgPreview(this.picValue);
        },
        imgPreview(file) {
          let self = this;
          let Orientation;
          // 去获取拍照时的信息,解决拍出来的照片旋转问题
          Exif.getData(file, function() {
            Orientation = Exif.getTag(this, 'Orientation');
          });
          // 看支持不支持FileReader
          if (!file || !window.FileReader) return;
    
          if (/^image/.test(file.type)) {
            // 创建一个reader
            let reader = new FileReader();
            // 将图片2将转成 base64 格式
            reader.readAsDataURL(file);
            // 读取成功后的回调
            reader.onloadend = function () {
              let result = this.result;
              let img = new Image();
              img.src = result;
              // 判断图片是否大于100K,是就直接上传,反之压缩图片
              if (this.result.length <= (100 * 1024)) {
                self.headerImage = this.result;
                self.postImg();
              } else {
                img.onload = function () {
                  let data = self.compress(img, Orientation);
                  self.headerImage = data;
                  self.postImg();
                };
              }
            };
          }
        },
        postImg() {
          // 这里写接口
        },
        rotateImg(img, direction, canvas) {
          // 最小与最大旋转方向,图片旋转4次后回到原方向
          const min_step = 0;
          const max_step = 3;
          if (img == null) return;
          // img的高度和宽度不能在img元素隐藏后获取,否则会出错
          let height = img.height;
          let width = img.width;
          let step = 2;
          if (step == null) {
            step = min_step;
          }
          if (direction === 'right') {
            step++;
            // 旋转到原位置,即超过最大值
            step > max_step && (step = min_step);
          } else {
            step--;
            step < min_step && (step = max_step);
          }
          // 旋转角度以弧度值为参数
          let degree = step * 90 * Math.PI / 180;
          let ctx = canvas.getContext('2d');
          switch (step) {
            case 0:
              canvas.width = width;
              canvas.height = height;
              ctx.drawImage(img, 0, 0);
              break;
            case 1:
              canvas.width = height;
              canvas.height = width;
              ctx.rotate(degree);
              ctx.drawImage(img, 0, -height);
              break;
            case 2:
              canvas.width = width;
              canvas.height = height;
              ctx.rotate(degree);
              ctx.drawImage(img, -width, -height);
              break;
            case 3:
              canvas.width = height;
              canvas.height = width;
              ctx.rotate(degree);
              ctx.drawImage(img, -width, 0);
              break;
          }
        },
        compress(img, Orientation) {
          let canvas = document.createElement('canvas');
          let ctx = canvas.getContext('2d');
          // 瓦片canvas
          let tCanvas = document.createElement('canvas');
          let tctx = tCanvas.getContext('2d');
          let initSize = img.src.length;
          let width = img.width;
          let height = img.height;
          // 如果图片大于四百万像素,计算压缩比并将大小压至400万以下
          let ratio;
          if ((ratio = width * height / 4000000) > 1) {
            console.log('大于400万像素');
            ratio = Math.sqrt(ratio);
            width /= ratio;
            height /= ratio;
          } else {
            ratio = 1;
          }
          canvas.width = width;
          canvas.height = height;
          //        铺底色
          ctx.fillStyle = '#fff';
          ctx.fillRect(0, 0, canvas.width, canvas.height);
          // 如果图片像素大于100万则使用瓦片绘制
          let count;
          if ((count = width * height / 1000000) > 1) {
            console.log('超过100W像素');
            count = ~~(Math.sqrt(count) + 1); // 计算要分成多少块瓦片
            //            计算每块瓦片的宽和高
            let nw = ~~(width / count);
            let nh = ~~(height / count);
            tCanvas.width = nw;
            tCanvas.height = nh;
            for (let i = 0; i < count; i++) {
              for (let j = 0; j < count; j++) {
                tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
                ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
              }
            }
          } else {
            ctx.drawImage(img, 0, 0, width, height);
          }
          // 修复ios上传图片的时候 被旋转的问题
          if (Orientation !== '' && Orientation !== 1) {
            switch (Orientation) {
              case 6:// 需要顺时针(向左)90度旋转
                this.rotateImg(img, 'left', canvas);
                break;
              case 8:// 需要逆时针(向右)90度旋转
                this.rotateImg(img, 'right', canvas);
                break;
              case 3:// 需要180度旋转
                this.rotateImg(img, 'right', canvas);// 转两次
                this.rotateImg(img, 'right', canvas);
                break;
            }
          }
          // 进行最小压缩
          let ndata = canvas.toDataURL('image/jpeg', 0.7);
          console.log('压缩前:' + initSize);
          console.log('压缩后:' + ndata.length);
          console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + '%');
          tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
          return ndata;
        },
      }
    };
    </script>
    
    <style lang="less" scoped>
    *{
      margin: 0;
      padding: 0;
    }
    /* .show {
       100px;
      height: 100px;
      overflow: hidden;
      position: relative;
      border-radius: 50%;
      border: 1px solid #d5d5d5;
    }
    .picture {
       100%;
      height: 100%;
      overflow: hidden;
      background-position: center center;
      background-repeat: no-repeat;
      background-size: cover;
    } */
    .havaDataimg{
      position: relative;
       100%;
      height: 100%;
      border: 1px solid #eeeeec;
      overflow: hidden;
      .img_wap{
         100%;
        height: 0px;
        position: relative;
        padding-bottom: 56.25%;
        img{
           100%;
          position: absolute;
          top: -30%;
          left: 0px;
        }
      }
    }
    </style>

     4引入组件使用

    import uploadImg from '@/components/upload/prescriptionUploadImg';
    
    
    components: {
        'uploadImg': uploadImg,
      },
    
    
    
    
    
    <uploadImg :imgUrl="pic_url" :fileName="'Image'" @uploadSuccess="addImgUrl" @removeImg="removeImgUrl"></uploadImg>
    

      

  • 相关阅读:
    软件工程个人作业01
    个人冲刺——(五)
    个人冲刺——(四)
    个人冲刺——(三)
    个人冲刺——(二)
    个人冲刺——(一)
    单词统计
    第十周学习总结
    第九周学习总结
    用户模板场景分析
  • 原文地址:https://www.cnblogs.com/yangzhenhong/p/11023586.html
Copyright © 2020-2023  润新知