资讯专栏INFORMATION COLUMN

JS 下载文件方法分享(解决图片文件无法直接下载和 IE兼容问题)

awesome23 / 2999人阅读

摘要:场景简介由于业务需要,经常遇到下载各类文件的需求,其中最头疼的莫过于前端下载图片了,直接给个图片文件地址会变成直接打开图片,而不是弹窗提示另存为,研究了下前端实现文件下载最便捷的方法还是创建标签,写入属性实现点击下载,但这在浏览器上的实现又

场景简介
由于业务需要,经常遇到下载各类文件的需求,其中最头疼的莫过于前端下载图片了,直接给个图片文件地址会变成直接打开图片,而不是弹窗提示另存为,研究了下前端实现文件下载最便捷的方法还是创建 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;
  }
}
好啦,希望该方法能够解决大家在下载文件特别是图片时遇到的问题 ^ - ^

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101204.html

相关文章

  • iconfont实践小结

    摘要:所以实现小图标时雪碧图跟图标字体会在一个网站共存,自定义图标字体为什么比较耗时,且太复杂图标无法实现请往下看开发流程就了解了。参考资料细谈浅谈图标字体向下兼容优雅降级技术绘制小图标技巧雪碧图图标字体矢量小图标设计本文对应源码源码地址演示地址 showImg(https://segmentfault.com/img/bVRnAC?w=431&h=220); 之前写了一篇关于雪碧图的博文,...

    bitkylin 评论0 收藏0
  • html&&css

    摘要:标准模式的排版和运作模式都是以该浏览器支持的最高标准运行。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。控制表单控件的禁用状态。首先,巧妙的使用这一标记,将游览器从所有情况中分离出来。 1.Doctype作用?标准模式与兼容模式各有什么区别 声明位于位于HTML文档中的第一行,处于 标签之前。告知浏览器的解析器,用什么文档标准解析这个文档。DOCTYPE不存在...

    gggggggbong 评论0 收藏0
  • html&&css

    摘要:标准模式的排版和运作模式都是以该浏览器支持的最高标准运行。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。控制表单控件的禁用状态。首先,巧妙的使用这一标记,将游览器从所有情况中分离出来。 1.Doctype作用?标准模式与兼容模式各有什么区别 声明位于位于HTML文档中的第一行,处于 标签之前。告知浏览器的解析器,用什么文档标准解析这个文档。DOCTYPE不存在...

    eccozhou 评论0 收藏0
  • 前端学习笔记(CSS、JS基础篇)

    摘要:搜索引擎中有一个爬虫模块,在页面中使用诸如等强调式的标签,有利于,说白了就是有利于被搜索到。定位相对定位不影响元素本身特性不使元素脱离文档流。定时器如果是由事件控制的,要先关再开,避免多次触发而混乱。 CSS篇 注意:css注释使用/ /,而不是或者//,否则很容易导致不明错误!!! div padding:内边距。盒子内容与盒子边框的距离设置,相当于给盒子加了厚度,使用此属性后会改...

    caikeal 评论0 收藏0
  • 前端学习笔记(CSS、JS基础篇)

    摘要:搜索引擎中有一个爬虫模块,在页面中使用诸如等强调式的标签,有利于,说白了就是有利于被搜索到。定位相对定位不影响元素本身特性不使元素脱离文档流。定时器如果是由事件控制的,要先关再开,避免多次触发而混乱。 CSS篇 注意:css注释使用/ /,而不是或者//,否则很容易导致不明错误!!! div padding:内边距。盒子内容与盒子边框的距离设置,相当于给盒子加了厚度,使用此属性后会改...

    xietao3 评论0 收藏0

发表评论

0条评论

awesome23

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<