前端js完成字符串/图片/excel文件下载

web开辟中,假如你想让用户下载或许导出一个文件,应当怎么做呢?
传统的做法是在后端存储或许立即天生一个文件来供应下载功用,如许的上风是可以做权限掌握、数据二次处置惩罚,但瑕玷是须要分外提议要求、增大服务端压力、下载速度慢。

但随着HTML5的规范宣布,我们已可以做到只前端来下载种种文件了。

后端相应式下载

在通例的HTTP应对中,
Content-Disposition 音讯头指导复兴的内容该以何种情势展现,是以内联的情势(即网页或许页面的一部分),照样以附件的情势下载并保留到当地。

HTTP场景中,第一个参数或许是inline(默许值,示意复兴中的音讯体味以页面的一部分或许悉数页面的情势展现),或许是attachment(意味着音讯体应当被下载到当地;大多数浏览器会显现一个“保留为”的对话框,将filename的值预填为下载后的文件名)。

我们在后端相应头中只需设置该头部信息,即可下载为文件,而不是要求并展现:

Content-Type: text/html; charset=utf-8
Content-Disposition: attachment; filename="cool.html"

但须要注重的是,假如想要用这类体式格局下载文件,不能运用AJAX的体式格局,而是应当新建一个<a>标签,模仿点击下载。原由于处于平安性斟酌,JavaScript没法与磁盘举行交互,因而AJAX取得的内容将被保留在内存中,而不是磁盘上。

Nginx增加header头下载

location ~ \.(jpg|jpeg|png|bmp|ico|gif|swf)$ {
    add_header Content-Disposition 'attachment; filename="cool.html"';
}

和后端一样的道理,只不过头部信息经由过程Nginx一致增加。

前端下载:<a>标签的download属性

此属性指导浏览器下载
URL而不是导航到它,因而将提醒用户将其保留为当地文件。假如属性有一个值,那末它将作为下载的文件名运用。此属性对许可的值没有限定,然则
/
\会被转换为下划线。

  1. 此属性仅适用于同源 URLs
  2. 只管HTTP URL须要位于统一源中,然则可以运用 blob: URLsdata: URLs ,以轻易用户下载 JavaScript 体式格局天生的内容(比方运用在线画图的Web运用建立的照片)。

通例的<a>标签,用于链接的跳转,如新的页面,那末假如我们给<a>标签加上download属性,就可以很简单的让用户保留新的html页面。

<a download="PHP完成并发要求.html" href="https://segmentfault.com/a/1190000016343861">PHP完成并发要求</a>

天生并下载字符串文件

起首我们须要相识一个特别的数据花样:Blob

Blob数据

Blob(Binary Large Object,二进制范例的大对象),示意一个不可变的原始数据的类文件对象,我们上传文件时经常使用的File对象就继续于Blob,并举行了扩大用于支撑用户体系上的文件。

我们只能经由过程Blob()组织函数来建立一个新的Blob对象:

Blob(blobParts[, options])

// 建立一个json范例的Blob对象,支撑传入同范例数据的一个数组
var debug = {hello: "world"};
var blob = new Blob([JSON.stringify(debug, null, 2)],
  {type : 'application/json'});

// 此时blob的值
// Blob(22) {size: 22, type: 'application/json'}

Blob对象存在两个只读属性:

size: Blob 对象中所包括数据的大小(字节)。

type: 一个字符串,表明该Blob对象所包括数据的MIME范例。假如范例未知,则该值为空字符串。

URL对象和下载字符串文件

URL 接口是一个用来建立 URLs 的对象,包括两个静态要领:

objectURL = URL.createObjectURL(blob)

建立一个
URL(DOMString),包括一个唯一的blob链接(该链接协定为以blob:,后跟唯一标识浏览器中的对象的掩码)。这个 URL 的生命周期和建立它的窗口中的 document 绑定。

URL.revokeObjectURL(objectURL)
烧毁之前运用URL.createObjectURL()要领建立的URL实例。浏览器会在文档退出的时刻自动开释它们,然则为了取得最好机能和内存运用状况,你应当在平安的机遇主动开释掉它们。

var url = URL.createObjectURL(blob);
// 此时url的值,跟document绑定,所以每一个页面建立的字符串均差别
// blob:https://developer.mozilla.org/defe53c2-2882-43c6-b275-db2a57959789

此时,我们在页面中建立一个新<a>标签,点击即可下载我们想要的文件:

<a href="blob:https://developer.mozilla.org/58702010-433d-4097-990f-e483d84cd02a" download="file.json">下载文件链接</a>

FileReader读取Blob数据

想要读取Blob数据的唯一要领是FileReader

FileReader 对象许可Web运用程序异步读取存储在用户盘算机上的文件(或原始数据缓冲区)的内容,运用
File
Blob 对象指定要读取的文件或数据。

个中File对象可所以来自用户在一个<input>元素上挑选文件后返回的FileList对象,也可以来自拖放操纵天生的 DataTransfer对象,还可所以来自由一个HTMLCanvasElement上实行mozGetAsFile()要领后返回效果。

该对象包括3个属性:

FileReader.error
一个DOMException,示意在读取文件时发作的毛病 。

FileReader.readyState
示意FileReader状况的数字。取值以下:

常量名    值    形貌
EMPTY    0    还没有加载任何数据.
LOADING    1    数据正在被加载.
DONE    2    已完成悉数的读取要求.

FileReader.result
文件的内容。该属性仅在读取操纵完成后才有用,数据的花样取决于运用哪一个要领来启动读取操纵。

包括6个事宜处置惩罚:onabort,onerror,onload,onloadstart,onloadend,onprogress,这些不再细致申明,由于 FileReader 继续自EventTarget,所以一切这些事宜也可以经由过程addEventListener要领运用。

包括5个要领:

FileReader.abort()

中断读取操纵。在返回时,readyState属性为DONE。

FileReader.readAsArrayBuffer()
最先读取指定的 Blob中的内容, 一旦完成, result 属性中保留的将是被读取文件的 ArrayBuffer 数据对象.

FileReader.readAsBinaryString()
最先读取指定的Blob中的内容。一旦完成,result属性中将包括所读取文件的原始二进制数据。

FileReader.readAsDataURL()
最先读取指定的Blob中的内容。一旦完成,result属性中将包括一个data: URL花样的字符串以示意所读取文件的内容。

FileReader.readAsText()
最先读取指定的Blob中的内容。一旦完成,result属性中将包括一个字符串以示意所读取的文件内容。

因而我们可以直接读取Blob对象的数据:

var reader = new FileReader();
reader.addEventListener("loadend", function() {
   console.log(reader.result);
});
reader.readAsDataURL(blob);
// 此时result的值
// data:application/json;base64,ewogICJoZWxsbyI6ICJ3b3JsZCIKfQ==
reader.readAsText(blob);
// 此时result的值
// {
//     "hello": "world"
// }

下载图片

除了下载手动天生的字符串或对象,我们还能供应下载图片的功用,一方面能用于支撑Canvas画图的保留功用,一方面能供应批量下载图片等高等功用。

除了浏览器自带的右键保留,我们还可以这么做来下载图片:

// 经由过程src猎取图片的blob对象
function getImageBlob(url, cb) {
    var xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.responseType = "blob";
    xhr.onload = function() {
        if (this.status == 200) {
            cb(this.response);
        }
    };
    xhr.send();
}

let reader = new FileReader();
reader.addEventListener("loadend", function() {
   console.log(reader.result);
});
getImageBlob('https://cdn.segmentfault.com/v-5c4ec07f/global/img/user-64.png', function(blob){
    // 读取来看下下载的内容
    reader.readAsDataURL(blob);
    // 终究天生的字符串
    // data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAA...
    // 天生下载用的URL对象
    let url = URL.createObjectURL(blob);
    // 天生一个a标签,并模仿点击,即可下载,批量下载同理
    let aDom = aDom = document.createElement('a');
    aDom.href = url;
    aDom.download = 'download.json';
    aDom.text = '下载文件';
    document.getElementsByTagName('body')[0].appendChild(aDom);
    aDom.click();
});

下载excel文件等

假如你邃晓了下载的道理,那末一切的内容都可以明白,只不过是转换成对应的花样罢了,固然,庞杂花样的文档不须要你本身去设置,可以引入第三方库,在excel文档方面我挑选用 tableExport库

// 引入CDN文件
'https://cdn.bootcss.com/xlsx/0.14.1/xlsx.core.min.js',
'https://cdn.bootcss.com/FileSaver.js/2014-11-29/FileSaver.min.js',
'https://cdn.bootcss.com/TableExport/5.2.0/js/tableexport.min.js'

// 绑定下载事宜,这个是我本身的场景下代码,能够不适合人人,详细的参考官方文档
const tableDom = $('#table');
$('.table-exportBtn', tableDom).on('click', function () {
    const tableExport = tableDom.tableExport({
        formats: ['xlsx', 'txt'],
        filename: '表格下载',
        exportButtons: false
    });
    const type = $(this).data().type;
    const exportData = tableExport.getExportData()[tableDom[0].id][type];
    const {data, mimeType, filename, fileExtension, merges, RTL, sheetname} = exportData;
    // 源码里才看到完全参数,官方文档没有写全,致使下载的文件花样毛病
    tableExport.export2file(data, mimeType, filename, fileExtension, merges, RTL, sheetname);
});

默许的要领会自动天生下载按钮,但假如你想自定义下载功用,参考 exportButtons: false 设置 一节,但这个文档有题目,export2file参数不完全,致使下载的xlsx文件一向花样毛病,经由过程检察源码,须要写全参数才可以,上面的示例里已写出。

tableExport库源码

我们可以看下tableExport导出文件的中心代码,其导出为excel花样比较庞杂,由xlsx.core.min.js来完成:

/**
     * Exports and downloads the file
     * @memberof TableExport.prototype
     * @param data {String}
     * @param mime {String} mime type
     * @param name {String} filename
     * @param extension {String} file extension
     * @param merges {Object[]}
     * @param RTL {Boolean}
     */
    export2file: function(data, mime, name, extension, merges, RTL, sheetname) {
      var format = extension.slice(1);
      data = this.getRawData(data, extension, name, merges, RTL, sheetname);

      if (_isMobile && (format === _FORMAT.CSV || format === _FORMAT.TXT)) {
        // 拼集指定花样的data:范例 URI
        var dataURI = "data:" + mime + ";" + this.charset + "," + data;
        this.downloadDataURI(dataURI, name, extension);
      } else {
        // TODO: error and fallback when `saveAs` not available
        saveAs(new Blob([data], { type: mime + ";" + this.charset }), name + extension, true);
      }
    },
    // 先建立<a>标签,然后供应href和download属性,并模仿点击
    downloadDataURI: function(dataURI, name, extension) {
      var encodedUri = encodeURI(dataURI);
      var link = document.createElement("a");
      link.setAttribute("href", encodedUri);
      link.setAttribute("download", name + extension);
      document.body.appendChild(link);
      link.click();
    },

xlsx文件导出导出

还没有细致研讨,感兴趣的可以检察其js-xlsx Github项目

第三方库

上面我们重要讲了下载背地的道理,你可以本身封装,也可以运用现成的第三方库,如 download.js ,这个能供应大部分经常使用数据的下载;但假如你是要下载表格数据为excel花样,照样引荐 tableExport.js 及其依靠组件。

参考资料

  1. MDN-a: https://developer.mozilla.org…
  2. MDN-blob: https://developer.mozilla.org…
  3. 掘金-细说Web API中的Blob:https://juejin.im/post/59e35d…
  4. MDN-URL: https://developer.mozilla.org…
  5. MDN-FileReader: https://developer.mozilla.org…
  6. 博客园-js 猎取图片url的Blob值并预览:https://www.cnblogs.com/tujia…
  7. tableExport文档:https://tableexport.v5.travis…
  8. 谢谢 @Oliveryoung 供应的其他解决方案
  9. MDN-Content-Disposition: https://developer.mozilla.org…
  10. Ajax要求没法下载文件的缘由: https://blog.csdn.net/w405722…
  11. Github-download.js: https://github.com/rndme/down…
    原文作者:赵帅强
    原文地址: https://segmentfault.com/a/1190000018143902
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞