關於vue項目中移動端實現用戶選擇照片、照片裁剪、一次上傳多張圖片(仿微信發朋友圈)功能。

關於vue項目中移動端實現用戶選擇照片、照片裁剪、一次上傳多張圖片功能(仿微信發朋友圈)。

最終要實現的效果如下圖所示:

在這裏插入圖片描述
在這裏插入圖片描述

涉及的功能有

1、圖片的選擇
2、圖片從手機相機選擇、拍照
3、圖片選擇後的裁剪
4、圖片在頁面的顯示效果
5、圖片的刪除
6、base64圖片轉化爲file類型的文件
7、圖片的上傳

首先安裝cropperjs 和exif-js 裁剪依賴這兩個包
cnpm install --save cropperjs exif-js

圖片的上傳相關代碼

在這裏插入圖片描述

圖片從手機相機選擇、拍照

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
圖片選擇後的裁剪

initilize(opt) {
      let self = this;
      this.options = opt;
      //創建dom
      this.createElement();
      this.resultObj = opt.resultObj;
      //初始化裁剪對象
      this.cropper = new Cropper(this.preview, {
        aspectRatio: opt.aspectWithRatio / opt.aspectHeightRatio,
        autoCropArea: opt.autoCropArea || 0.8,
        viewMode: 2,
        guides: true,
        cropBoxResizable: true, //是否通過拖動來調整剪裁框的大小
        cropBoxMovable: true, //是否通過拖拽來移動剪裁框。
        dragCrop: false,
        dragMode: "move", //‘crop’: 可以產生一個新的裁剪框3 ‘move’: 只可以移動3 ‘none’: 什麼也不處理
        center: true,
        zoomable: true, //是否允許放大圖像。
        zoomOnTouch: true, //是否可以通過拖動觸摸來放大圖像。
        scalable: true,
        // minCropBoxHeight: 750,
        // minCropBoxWidth: 750,
        background: false,
        checkOrientation: true,
        checkCrossOrigin: true,
        zoomable: false,
        zoomOnWheel: false,
        center: false,
        toggleDragModeOnDblclick: false,
        ready: function() {
          if (opt.aspectRatio == "Free") {
            let cropBox = self.cropper.cropBox;
            cropBox.querySelector("span.cropper-view-box").style.outline =
              "none";
            self.cropper.disable();
          }
        }
      });
    },
    //創建一些必要的DOM,用於圖片裁剪
    createElement() {
      //初始化圖片爲空對象
      this.preview = null;
      let str =
        '<div><img id="clip_image" src="originUrl"></div><button type="button" id="cancel_clip">取消</button><button type="button" id="clip_button">確定</button>';
      str +=
        '<div class="crop_loading"><div class="crop_content"><div class="crop_text">圖片修剪中...</div></div></div>';
      str +=
        '<div class="crop_success"><div class="crop_success_text">上傳成功</div></div></div>';
      let body = document.getElementsByTagName("body")[0];
      this.reagion = document.createElement("div");
      this.reagion.id = "clip_container";
      this.reagion.className = "container";
      this.reagion.innerHTML = str;
      body.appendChild(this.reagion);
      this.preview = document.getElementById("clip_image");
      //綁定一些方法
      this.initFunction();
    },
    //初始化一些函數綁定
    initFunction() {
      let self = this;
      this.clickBtn = document.getElementById("clip_button");
      this.cancelBtn = document.getElementById("cancel_clip");
      //確定事件
      this.addEvent(this.clickBtn, "click", function() {
        self.crop();
      });
      //取消事件
      this.addEvent(this.cancelBtn, "click", function() {
        self.destoried();
      });
      //清空input的值
      this.addEvent(this.fileObj, "click", function() {
        this.value = "";
      });
    },
    //外部接口,用於input['file']對象change時的調用
    clip(e, opt) {
      let self = this;

      this.fileObj = e.srcElement;

      let files = e.target.files || e.dataTransfer.files;

      if (!files.length) return false; //不是圖片直接返回

      //調用初始化方法
      this.initilize(opt);

      //獲取圖片文件資源
      this.picValue = files[0];

      //調用方法轉成url格式
      this.originUrl = this.getObjectURL(this.picValue);

      //每次替換圖片要重新得到新的url
      if (this.cropper) {
        this.cropper.replace(this.originUrl);
      }
    },
    //圖片轉碼方法
    getObjectURL(file) {
      let url = null;
      if (window.createObjectURL != undefined) {
        // basic
        url = window.createObjectURL(file);
      } else if (window.URL != undefined) {
        // mozilla(firefox)
        url = window.URL.createObjectURL(file);
      } else if (window.webkitURL != undefined) {
        // webkit or chrome
        url = window.webkitURL.createObjectURL(file);
      }
      return url;
    },
    //點擊確定進行裁剪
    crop() {
      let self = this;
      let image = new Image();
      let croppedCanvas;
      let roundedCanvas;

      // Crop
      document.querySelector(".crop_loading").style.display = "block";

      setTimeout(function() {
        croppedCanvas = self.cropper.getCroppedCanvas();
        // Round
        roundedCanvas = self.getRoundedCanvas(croppedCanvas);

        let imgData = roundedCanvas.toDataURL();
        image.src = imgData;

        //判斷圖片是否大於100k,不大於直接上傳,反之壓縮
        if (imgData.length < 100 * 1024) {
          // self.resultObj.src = imgData;
          //圖片上傳
          self.postImg(imgData);
        } else {
          image.onload = function() {
            //壓縮處理
            let data = self.compress(image, self.Orientation);
            // self.resultObj.src = data;
            //圖片上傳
            self.postImg(data);
          };
        }
      }, 20);
    },
    //獲取裁剪圖片資源
    getRoundedCanvas(sourceCanvas) {
      let canvas = document.createElement("canvas");
      let context = canvas.getContext("2d");
      let width = sourceCanvas.width;
      let height = sourceCanvas.height;

      canvas.width = width;
      canvas.height = height;

      context.imageSmoothingEnabled = true;
      context.drawImage(sourceCanvas, 0, 0, width, height);
      context.globalCompositeOperation = "destination-in";
      context.beginPath();
      context.rect(0, 0, width, height);
      context.fill();

      return canvas;
    },
    //銷燬原來的對象
    destoried() {
      let self = this;
      //移除事件
      this.removeEvent(this.clickBtn, "click", null);
      this.removeEvent(this.cancelBtn, "click", null);
      this.removeEvent(this.fileObj, "click", null);
      //移除裁剪框
      this.reagion.parentNode.removeChild(this.reagion);

      //銷燬裁剪對象
      this.cropper.destroy();
      this.cropper = null;
    },
    //圖片上傳
    postImg(imageData) {
      console.log(imageData);
      this.$emit("callback", imageData);
      //這邊寫圖片的上傳
      let self = this;
      self.destoried();
      this.imgList.push(imageData);
    },
    //圖片旋轉
    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) {
        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/png", 0.1);
      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;
    },
    //添加事件
    addEvent(obj, type, fn) {
      if (obj.addEventListener) {
        obj.addEventListener(type, fn, false);
      } else {
        obj.attachEvent("on" + type, fn);
      }
    },
    //移除事件
    removeEvent(obj, type, fn) {
      if (obj.removeEventListener) {
        obj.removeEventListener(type, fn, false);
      } else {
        obj.detachEvent("on" + type, fn);
      }
    }

圖片在頁面的顯示效果
暫無
圖片的刪除
在這裏插入圖片描述
base64圖片轉化爲file類型的文件
bytes = window.atob(this.imgList[i].split(',')[1]);

    var array = [];
        array.push(bytes.charCodeAt(j));
  var  blob = new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
    form.append("file", blob, Date.now() + '.jpg');
    

圖片的上傳
暫無

最終效果:
在這裏插入圖片描述
在這裏插入圖片描述
圖片裁剪參考:https://blog.csdn.net/ch83430...

ps: 需要源碼的請聯繫我(請尊重一下別人的勞動成果,源碼需要付費10元哦。):
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章