JS 下載文件方法分享(解決圖片文件無(wú)法直接下載和 IE兼容問(wèn)題)

場(chǎng)景簡(jiǎn)介

由于業(yè)務(wù)需要,經(jīng)常遇到下載各類文件的需求,其中最頭疼的莫過(guò)于前端下載圖片了,直接給個(gè)圖片文件地址會(huì)變成直接打開(kāi)圖片伤溉,而不是彈窗提示另存為,研究了下前端實(shí)現(xiàn)文件下載最便捷的方法還是創(chuàng)建 a 標(biāo)簽妻率,寫入download 屬性實(shí)現(xiàn)點(diǎn)擊下載乱顾,但這在 ie 瀏覽器上的實(shí)現(xiàn)又與一般瀏覽器不同,于是摸索之后寫了個(gè)通用的下載方法宫静,既可用來(lái)下載文件也可下載圖片走净,希望能夠幫到大家。

npm 安裝使用

npm install --save ly-downloader

附上npm的傳送門囊嘉,https://www.npmjs.com/package/ly-downloader

使用時(shí)需傳入3個(gè)參數(shù) download(type, data, name):

  • type: 1 或 2( 用于判斷傳入的是地址還是canvas對(duì)象 )
  • data: type = 1 時(shí)傳入文件地址温技; type = 2 時(shí)傳入一個(gè)canvas對(duì)象( 配合html2canvas使用 )
  • name: 下載圖片默認(rèn)文件名( type = 1 時(shí)設(shè)置’'為地址默認(rèn)文件名, type = 2 時(shí) name 不能為空 )
    注:name 參數(shù)雖然只有在下載文件類型為圖片時(shí)生效,但為避免出錯(cuò)都需要傳入一個(gè)值
    例:download(1, url, ‘’) 或 download(2, canvas對(duì)象, ‘圖片附件’)

以 Vue 中組件使用為例

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

思路簡(jiǎn)介

  • 創(chuàng)建 a 標(biāo)簽扭粱,href 傳入文件地址舵鳞,download 寫上文件名,觸發(fā)點(diǎn)擊事件實(shí)現(xiàn)文件另存為(設(shè)置文件名對(duì)非圖片類型文件無(wú)效)
  • 圖片類型文件使用地址下載會(huì)直接打開(kāi)琢蛤,需要將圖片地址利用 canvas 獲取 baase64 格式文件蜓堕,再由 base64 轉(zhuǎn)換為 blob 類型,最后利用URL.createObjectURL() 方法獲取 blob 文件的地址博其,此類型地址傳入 a 標(biāo)簽可實(shí)現(xiàn)不打開(kāi)直接下載
  • type = 2 這種情況是個(gè)人經(jīng)常遇到頁(yè)面截圖下載的場(chǎng)景套才,配合插件html2canvas 來(lái)使用非常方便,原理還是根據(jù) canvas 對(duì)象一步步轉(zhuǎn)換成 blob 對(duì)象

源碼

'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = download;
/**
 * 下載文件
 *
 * @export
 * @param {*} type 設(shè)置接收數(shù)據(jù)類型 參數(shù) 1 或 2
 * @param {*} data type為 1 時(shí) data 為文件地址慕淡; type為 2 時(shí) data 為canvas對(duì)象
 * @param {*} name 當(dāng)文件為圖片類型時(shí)需設(shè)置文件名
 */
function download(type, data, name) {
  if (type == 1) {
    var url = data;
    // 通過(guò)地址判斷是否為圖片類型文件
    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.click();
        }
      });
    } else {
      var a = document.createElement('a');
      a.download = name;
      a.href = url;
      a.click();
    }
  } 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.click();
    }
  }
}

/**
 * 將 base64 轉(zhuǎn)換位 blob 對(duì)象
 * blob 存儲(chǔ) 2進(jìn)制對(duì)象的容器
 * @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 });
}

/**
 * 將圖片地址轉(zhuǎn)換為 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;
  }
}
好啦背伴,希望該方法能夠解決大家在下載文件特別是圖片時(shí)遇到的問(wèn)題 ^ - ^,此文做筆記為主!

作者:jyliyue
來(lái)源:CSDN
原文:https://blog.csdn.net/jyliyue/article/details/83020875
版權(quán)聲明:本文為博主原創(chuàng)文章傻寂,轉(zhuǎn)載請(qǐng)附上博文鏈接息尺!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市疾掰,隨后出現(xiàn)的幾起案子搂誉,更是在濱河造成了極大的恐慌,老刑警劉巖静檬,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炭懊,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡拂檩,警方通過(guò)查閱死者的電腦和手機(jī)侮腹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)广恢,“玉大人凯旋,你說(shuō)我怎么就攤上這事《っ裕” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵钠署,是天一觀的道長(zhǎng)糠聪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)谐鼎,這世上最難降的妖魔是什么舰蟆? 我笑而不...
    開(kāi)封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮狸棍,結(jié)果婚禮上身害,老公的妹妹穿的比我還像新娘。我一直安慰自己草戈,他們只是感情好塌鸯,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著唐片,像睡著了一般丙猬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上费韭,一...
    開(kāi)封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天茧球,我揣著相機(jī)與錄音,去河邊找鬼星持。 笑死抢埋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播揪垄,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼穷吮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了福侈?” 一聲冷哼從身側(cè)響起酒来,我...
    開(kāi)封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肪凛,沒(méi)想到半個(gè)月后堰汉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伟墙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年翘鸭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戳葵。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡就乓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拱烁,到底是詐尸還是另有隱情生蚁,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布戏自,位于F島的核電站邦投,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏擅笔。R本人自食惡果不足惜志衣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望猛们。 院中可真熱鬧念脯,春花似錦、人聲如沸弯淘。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)耳胎。三九已至惯吕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間怕午,已是汗流浹背废登。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留郁惜,地道東北人堡距。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓甲锡,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親羽戒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缤沦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容