JS 下載檔案方法分享(解決圖片檔案無法直接下載和 IE相容問題)

毛哥小弟發表於2019-02-16

場景簡介

由於業務需要,經常遇到下載各類檔案的需求,其中最頭疼的莫過於前端下載圖片了,直接給個圖片檔案地址會變成直接開啟圖片,而不是彈窗提示另存為,研究了下前端實現檔案下載最便捷的方法還是建立 a 標籤,寫入download 屬性實現點選下載,但這在 ie 瀏覽器上的實現又與一般瀏覽器不同,於是摸索之後寫了個通用的下載方法,既可用來下載檔案也可下載圖片,希望能夠幫到大家。

npm 安裝使用

npm install –save ly-downloader

使用時需傳入3個引數 download(type, data, name):

  • type: 1 或 2( 用於判斷傳入的是地址還是canvas物件 )
  • data: type = 1 時傳入檔案地址; type = 2 時傳入一個canvas物件( 配合html2canvas使用 )
  • name: 下載圖片預設檔名( type = 1 時設定“為地址預設檔名, type = 2 時 name 不能為空 )

注:name 引數雖然只有在下載檔案型別為圖片時生效,但為避免出錯都需要傳入一個值
例:download(1, url, “) 或 download(2, canvas物件, `圖片附件`)

以 Vue 中元件使用為例

import download from `ly-downloader`
export default {
  methods: {
    // url = `你的檔案地址`
    _download (url) {
      download(1, url, `檔名`)
    },
  }
}

思路簡介

  • 建立 a 標籤,href 傳入檔案地址,download 寫上檔名,觸發點選事件實現檔案另存為(設定檔名對非圖片型別檔案無效)
  • 圖片型別檔案使用地址下載會直接開啟,需要將圖片地址利用 canvas 獲取 baase64 格式檔案,再由 base64 轉換為 blob 型別,最後利用URL.createObjectURL() 方法獲取 blob 檔案的地址,此型別地址傳入 a 標籤可實現不開啟直接下載
  • type = 2 這種情況是個人經常遇到頁面截圖下載的場景,配合外掛html2canvas 來使用非常方便,原理還是根據 canvas 物件一步步轉換成 blob 物件

原始碼

`use strict`;

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = download;
/**
 * 下載檔案
 *
 * @export
 * @param {*} type 設定接收資料型別 引數 1 或 2
 * @param {*} data type為 1 時 data 為檔案地址; type為 2 時 data 為canvas物件
 * @param {*} name 當檔案為圖片型別時需設定檔名
 */
function download(type, data, name) {
  if (type == 1) {
    var url = data;
    // 通過地址判斷是否為圖片型別檔案
    var ext = url.slice(url.lastIndexOf(`.`) + 1).toLowerCase();
    if (isImage(ext)) {
      convertUrlToBase64(url).then(function (base64) {
        var blob = convertBase64UrlToBlob(base64);
        // 下載
        if (myBrowser() == `IE`) {
          window.navigator.msSaveBlob(blob, name + `.jpg`);
        } else {
          var a = document.createElement(`a`);
          a.download = name;
          a.href = URL.createObjectURL(blob);
          a.style.display = `none`
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
        }
      });
    } else {
      var a = document.createElement(`a`);
      a.download = name;
      a.href = url;
      a.style.display = `none`
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    }
  } else {
    var dataURL = data.toDataURL(`image/jpeg`, 1.0);
    var base64 = {
      dataURL: dataURL,
      type: `image/jpg`,
      ext: `jpg`
    };
    var blob = convertBase64UrlToBlob(base64);
    // 下載
    if (myBrowser() == `IE`) {
      window.navigator.msSaveBlob(blob, name + `.jpg`);
    } else {
      var _a = document.createElement(`a`);
      _a.download = name;
      _a.href = URL.createObjectURL(blob);
      _a.style.display = `none`
      document.body.appendChild(_a);
      _a.click();
      document.body.removeChild(_a);
    }
  }
}

/**
 * 將 base64 轉換位 blob 物件
 * blob 儲存 2進位制物件的容器
 * @export
 * @param {*} base64
 * @returns
 */
function convertBase64UrlToBlob(base64) {
  var parts = base64.dataURL.split(`;base64,`);
  var contentType = parts[0].split(`:`)[1];
  var raw = window.atob(parts[1]);
  var rawLength = raw.length;
  var uInt8Array = new Uint8Array(rawLength);
  for (var i = 0; i < rawLength; i++) {
    uInt8Array[i] = raw.charCodeAt(i);
  }
  return new Blob([uInt8Array], { type: contentType });
}

/**
 * 將圖片地址轉換為 base64 格式
 *
 * @param {*} url
 */
function convertUrlToBase64(url) {
  return new Promise(function (resolve, reject) {
    var img = new Image();
    img.crossOrigin = `Anonymous`;
    img.src = url;
    img.onload = function () {
      var canvas = document.createElement(`canvas`);
      canvas.width = img.width;
      canvas.height = img.height;
      var ctx = canvas.getContext(`2d`);
      ctx.drawImage(img, 0, 0, img.width, img.height);
      var ext = img.src.substring(img.src.lastIndexOf(`.`) + 1).toLowerCase();
      var dataURL = canvas.toDataURL(`image/` + ext);
      var base64 = {
        dataURL: dataURL,
        type: `image/` + ext,
        ext: ext
      };
      resolve(base64);
    };
  });
}

// 判斷瀏覽器型別 
function myBrowser() {
  var userAgent = navigator.userAgent; //取得瀏覽器的userAgent字串
  if (userAgent.indexOf("OPR") > -1) {
    return "Opera";
  }; //判斷是否Opera瀏覽器 OPR/43.0.2442.991
  if (userAgent.indexOf("Firefox") > -1) {
    return "FF";
  } //判斷是否Firefox瀏覽器  Firefox/51.0
  if (userAgent.indexOf("Trident") > -1) {
    return "IE";
  } //判斷是否IE瀏覽器  Trident/7.0; rv:11.0
  if (userAgent.indexOf("Edge") > -1) {
    return "Edge";
  } //判斷是否Edge瀏覽器  Edge/14.14393
  if (userAgent.indexOf("Chrome") > -1) {
    return "Chrome";
  } // Chrome/56.0.2924.87
  if (userAgent.indexOf("Safari") > -1) {
    return "Safari";
  } //判斷是否Safari瀏覽器 AppleWebKit/534.57.2 Version/5.1.7 Safari/534.57.2
}

// 判斷檔案是否為圖片型別
function isImage(ext) {
  if (ext == `png` || ext == `jpg` || ext == `jpeg` || ext == `gif` || ext == `bmp`) {
    return true;
  }
}

好啦,希望該方法能夠解決大家在下載檔案特別是圖片時遇到的問題 ^ – ^

相關文章