js下载文件(兼容IE、QQ)

地址URL

方式一

window.downloadFile = function (sUrl) {
    //iOS devices do not support downloading. We have to inform user about this.
    if (/(iP)/g.test(navigator.userAgent)) {
        alert('Your device does not support files downloading. Please try again in desktop browser.');
        return false;
    }

    //If in Chrome or Safari - download via virtual link click
    if (window.downloadFile.isChrome || window.downloadFile.isSafari) {
        //Creating new link node.
        var link = document.createElement('a');
        link.href = sUrl;

        if (link.download !== undefined) {
            //Set HTML5 download attribute. This will prevent file from opening if supported.
            var fileName = sUrl.substring(sUrl.lastIndexOf('/') + 1, sUrl.length);
            link.download = fileName;
        }

        //Dispatching click event.
        if (document.createEvent) {
            var e = document.createEvent('MouseEvents');
            e.initEvent('click', true, true);
            link.dispatchEvent(e);
            return true;
        }
    }
   
    // Force file download (whether supported by server).
    if (sUrl.indexOf('?') === -1) {
        sUrl += '?download';
    }

    window.open(sUrl, '_self');
    return true;
}
window.downloadFile.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
window.downloadFile.isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;
问题

1、QQ浏览器下载文件会崩溃
1>将window.open(sUrl, '_self');改为window.open(sUrl, '_blank');
2>判断是否为QQ浏览器,如果是,则新窗口打开当前网址。

getBrowserInfo () { 
    var ua = navigator.userAgent.toLocaleLowerCase(); 
    var browserType=null; 
    if (ua.match(/msie/) != null || ua.match(/trident/) != null) { 
        browserType = "IE"; 
        browserVersion = ua.match(/msie ([\d.]+)/) != null ? ua.match(/msie ([\d.]+)/)[1] : ua.match(/rv:([\d.]+)/)[1]; 
    } else if (ua.match(/firefox/) != null) { 
        browserType = "火狐"; 
    }else if (ua.match(/ubrowser/) != null) { 
        browserType = "UC"; 
    }else if (ua.match(/opera/) != null) { 
        browserType = "欧朋"; 
    } else if (ua.match(/bidubrowser/) != null) { 
        browserType = "百度"; 
    }else if (ua.match(/metasr/) != null) { 
        browserType = "搜狗"; 
    }else if (ua.match(/tencenttraveler/) != null || ua.match(/qqbrowse/) != null) { 
        browserType = "QQ"; 
    }else if (ua.match(/maxthon/) != null) { 
        browserType = "遨游"; 
    }else if (ua.match(/chrome/) != null) { 
        var is360 = _mime("type", "application/vnd.chromium.remoting-viewer"); 
        function _mime(option, value) { 
            var mimeTypes = navigator.mimeTypes; 
            for (var mt in mimeTypes) { 
                if (mimeTypes[mt][option] == value) { 
                    return true; 
                } 
            } 
            return false; 
        } 
        if(is360){ 
            browserType = '360'; 
        }else{ 
            $('html').css("zoom",".80"); 
        } 
    }else if (ua.match(/safari/) != null) { 
        browserType = "Safari"; 
    } 
    return browserType
},
downloadFile(url) 
if (this.getBrowserInfo() === 'QQ') {        
  const { href } = this.$router.resolve({
      name: "donation",            
  });
  window.open(href, '_blank');
} 

2、IE浏览器接口没获取到链接地址
所以我把下载的地址写死了

window.location.origin + '/api/web/fundMessagePublic/download?id=' + id

兼容IE

判断

window.downloadFile.isIE = function () { 
if(!!window.ActiveXObject || "ActiveXObject" in window) 
    return true; 
else 
    return false; 
}

方式1

if (window.downloadFile.isIE()) {
    var elemIF = document.createElement("iframe");  
    elemIF.src = sUrl;  
    elemIF.style.display = "none";  
    document.body.appendChild(elemIF);
    elemIF.click()   
}

方式2

if (window.navigator.msSaveBlob) {
    try {
        window.navigator.msSaveBlob(url, downloadFileName);
    }
    catch (e) {
        console.log(e);
    }
}

方式二

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对象, ‘图片附件’)
import download from 'ly-downloader'

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.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 转换位 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;
  }
}

方式三

// 保存到本地并自动点击
function saveAs(data, name) {
    const urlObject = window.URL || window.webkitURL || window;
    const export_blob = new Blob([data]);
    const save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
    save_link.href = urlObject.createObjectURL(export_blob);
    save_link.download = name;
    save_link.click();
}
// 下载含有url的文件
function downloadUrlFile(url, fileName) {
    const url2 = url.replace(/\\/g, '/');
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url2, true);
    xhr.responseType = 'blob';
    //xhr.setRequestHeader('Authorization', 'Basic a2VybWl0Omtlcm1pdA==');
    // 为了避免大文件影响用户体验,建议加loading
    xhr.onload = () => {
        if (xhr.status === 200) {
            // 获取文件blob数据并保存
            saveAs(xhr.response, fileName);
        }
    };
    xhr.send();
}
downloadUrlFile(url, fileName);

文件流

const content = res.data;
const blob = new Blob([content])
const fileName = decodeURI(res.headers['content-disposition'].split(';')[1].split('=')[1]) || '文件.xlsx'            
if ('download' in document.createElement('a')) { // 非IE下载
    const elink = document.createElement('a')
    elink.download = fileName
    elink.style.display = 'none'
    elink.href = URL.createObjectURL(blob)
    document.body.appendChild(elink)
    elink.click()
    URL.revokeObjectURL(elink.href) // 释放URL 对象
    document.body.removeChild(elink)
} else { // IE10+下载
    navigator.msSaveBlob(blob, fileName)
}

兼容性说明

谷歌和火狐支持a标签的download属性,ie有自带的msSaveBlob方法,或者用其他方式实现。

下载说明

有时候你下载后发现直接打开了,只要不是在浏览器中打开,就是下载完成了。有可能电脑设置了下载自动使用某软件打开。还可以从浏览器中的下载记录去查看,有记录则下载成功,不必纠结。

相关文章

vue导出文件

网站导航

网站导航

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容