Vue使用mixins手寫壓縮圖片代碼

1、介紹

本文將介紹再Vue項目中經過js對圖片進行壓縮後使用。(純前端實現,不依賴後臺)前端

主要使用Canvas.toDataURL(type, encoderOptions)對圖片大小進行調整vue

參數 描述
type 圖片格式
encoderOptions 在指定圖片格式爲 image/jpeg 或 image/webp的狀況下,能夠從 0 到 1 的區間內選擇圖片的質量。

2、步驟

1.將圖片轉化爲 base64

使用 FileReader.readAsDataURL(file):該方法會讀取指定的 File 對象。讀取操做完成的時候,readyState 會變成已完成(DONE),並觸發 loadend 事件,同時 result 屬性將包含一個data:URL格式的字符串(base64編碼)以表示所讀取文件的內容。

reader.readAsDataURL 把圖片能轉換成 base64, 出發 reader.onload 事件對 image.src 賦值完成,觸發 image.onload 事件生成canvas,調用回調函數。web

clipboard.png

/**
 * 將圖片轉化爲base64
 */
imgBase64(file, callback) {
  // 看支持不支持FileReader
  if (!file || !window.FileReader) return;
  // 建立一個 Image 對象
  let image = new Image();
  // 綁定 load 事件處理器,加載完成後執行
  image.onload = function () {
    // 建立 canvas DOM 對象
    let canvas = document.createElement('canvas');
    // 返回一個用於在畫布上繪圖的環境, '2d' 指定了您想要在畫布上繪製的類型
    let ctx = canvas.getContext('2d');
    // 若是高度超標 // 參數,最大高度
    let MAX_HEIGHT = 3000;
    if (image.height > MAX_HEIGHT) {
      // 寬度等比例縮放 *=
      image.width *= MAX_HEIGHT / image.height;
      image.height = MAX_HEIGHT;
    }
    // 獲取 canvas的 2d 環境對象,
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    // 重置canvas寬高
    canvas.width = image.width;
    canvas.height = image.height;
    // 將圖像繪製到canvas上
    ctx.drawImage(image, 0, 0, image.width, image.height);

    callback(image, canvas);

  };
  if (/^image/.test(file.type)) {
    // 建立一個reader
    let reader = new FileReader();
    // 讀取成功後的回調
    reader.onload = function () {
      // 設置src屬性,瀏覽器會自動加載。
      // 記住必須先綁定事件,才能設置src屬性,不然會出同步問題。
      image.src = this.result;
    };
    // 將圖片將轉成 base64 格式
    reader.readAsDataURL(file);
  }
}

2.把base64轉換成file文件

/**
 * 把base64轉換成file文件
 */
convertBase64UrlToFile(dataurl, filename) {
  let arr = dataurl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]), n = bstr.length,
    u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, {type: mime});
}

3.ES6 Promise的簡單使用

function checkAndHandleCompression() {
  //當異步代碼執行成功時,咱們纔會調用resolve(...), 當異步代碼失敗時就會調用reject(...)
  return new Promise((resolve, reject) => {
    resolve('成功!') // 代碼正常執行!
  })
}

checkAndHandleCompression().then((data)=>{
  console.log(data) // print 成功!
});

4.對 Promise 填充代碼,檢查並壓縮圖片大小

若是圖片過大就使用Canvas.toDataURL(type, encoderOptions)對圖片進行壓縮,並將結果異步返回
/**
 * 檢查並壓縮圖片大小
 */
checkAndHandleCompression(file) {

  return new Promise((resolve, reject) => {

    this.imgBase64(file, (image, canvas) => {
      let maxSize = 2 * 1024; // 壓縮到2M如下 (單位KB)
      let fileSize = file.size / 1024; // 圖片大小 (單位KB)

      let uploadSrc, uploadFile;
      // 若是圖片大小大於maxSize,進行壓縮
      if (fileSize > maxSize) {
        uploadSrc = canvas.toDataURL(file.type, maxSize / fileSize);
        uploadFile = this.convertBase64UrlToFile(uploadSrc, file.name); // 轉成file文件
      } else {
        uploadSrc = image.src;
        uploadFile = file;
      }

      let compressedSize = uploadFile.size / 1024;// 壓縮後圖片大小 (單位KB)
      // 判斷圖片大小是否小於maxSize,若是大於則繼續壓縮至小於爲止
      if (compressedSize.toFixed(2) > maxSize) {
        this.checkAndHandleCompression(uploadFile);
      } else {
        let fileOptions = {uploadSrc, uploadFile};
        resolve(fileOptions);
      }
    });

  });

}

3、完整代碼

建立mixins/image-compress.jscanvas

export default {

  methods: {
    /**
     * 檢查並壓縮圖片大小
     */
    checkAndHandleCompression(file) {

      return new Promise((resolve, reject) => {

        this.imgBase64(file, (image, canvas) => {
          let maxSize = 2 * 1024; // 2M (單位KB)
          let fileSize = file.size / 1024; // 圖片大小 (單位KB)

          let uploadSrc, uploadFile;
          // 若是圖片大小大於maxSize,進行壓縮
          if (fileSize > maxSize) { 
            uploadSrc = canvas.toDataURL(file.type, maxSize / fileSize); // 轉換成DataURL
            uploadFile = this.convertBase64UrlToFile(uploadSrc, file.name); // 轉成file文件
          } else {
            uploadSrc = image.src;
            uploadFile = file;
          }

          let compressedSize = uploadFile.size / 1024;// 壓縮後圖片大小 (單位KB)
          // 判斷圖片大小是否小於maxSize,若是大於則繼續壓縮至小於爲止
          if (compressedSize.toFixed(2) > maxSize) {
            this.checkAndHandleUpload(uploadFile);
          } else {
            let fileOptions = {uploadSrc, uploadFile};
            resolve(fileOptions);
          }
        });

      });

    },

    /**
     * 將圖片轉化爲base64
     */
    imgBase64(file, callback) {
      // 看支持不支持FileReader
      if (!file || !window.FileReader) return;
      // 建立一個 Image 對象
      let image = new Image();
      // 綁定 load 事件處理器,加載完成後執行
      image.onload = function () {
        // 建立 canvas DOM 對象
        let canvas = document.createElement('canvas');
        // 返回一個用於在畫布上繪圖的環境, '2d' 指定了您想要在畫布上繪製的類型
        let ctx = canvas.getContext('2d');
        // 若是高度超標 // 參數,最大高度
        let MAX_HEIGHT = 3000;
        if (image.height > MAX_HEIGHT) {
          // 寬度等比例縮放 *=
          image.width *= MAX_HEIGHT / image.height;
          image.height = MAX_HEIGHT;
        }
        // 獲取 canvas的 2d 環境對象,
        // 能夠理解Context是管理員,canvas是房子
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // 重置canvas寬高
        canvas.width = image.width;
        canvas.height = image.height;
        // 將圖像繪製到canvas上
        ctx.drawImage(image, 0, 0, image.width, image.height);

        callback(image, canvas);

      };
      if (/^image/.test(file.type)) {
        // 建立一個reader
        let reader = new FileReader();
        // 讀取成功後的回調
        reader.onload = function () {
          // 設置src屬性,瀏覽器會自動加載。
          // 記住必須先綁定事件,才能設置src屬性,不然會出同步問題。
          image.src = this.result;
        };
        // 將圖片將轉成 base64 格式
        reader.readAsDataURL(file);
      }
    },

    /**
     * 把Base64轉換成file文件
     */
    convertBase64UrlToFile(dataurl, filename) {
      let arr = dataurl.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]), n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, {type: mime});
    }

  }
};

4、example

<template>
    ...
    
    <input type="file" @change="handleUploadImage"/>
    
    ...
</template>
<script>

  import imageUploadMixins from '@/mixins/image-compress';
  
  export default {
  
    mixins: [imageUploadMixins],
    
    ...
    
    methods:{
        handleUploadImage(e){
            let file = e.target.files[0];
            this.checkAndHandleCompression(file).then( fileOptions => {
                // let {uploadSrc, uploadFile} = fileOptions;
                
                // 壓縮完成使用 uploadSrc, uploadFile
                
                ...
                
            });
        }
    }
    
    ...
    
  }
</script>
<style>
    ...
</style>

5、參考連接

相關文章
相關標籤/搜索