Clark To Do The blog of Clark

前端导出文件方式

我们在日常开发中, 经常会遇到需要将查询结果导出为Excel, PDF等等文件的需求. 下面, 我将为大家介绍一下几种比较常见的导出方式.

1. 服务器转发方式

这种方式应该是应用的最普遍的方式了, 通常我们会将页面元素收集起来发送给服务端, 或者干脆直接调用服务端接口, 由服务端直接获取数据并拼装为对应的文件格式, 最后将数据拼入 HTTP Response 中并对 Header 处理, 最后返回给客户端, 实现文件下载.

通常对于 HTTP Header 处理方式如下:

  1. 添加 Content-type: <MIME Type>
  2. 添加 Content-Disposition: attachment; filename=”<file_name.ext>”
<?php

$file = $_GET['file'];

header('Content-type: application/excel');

header('Content-Disposition: attachment; filename="'.$file.'"');

?>

这种做法的好处是不会存在浏览器兼容性的问题, 以及后端含有丰富的文件处理框架, 例如: Java可以使用 Apache 的 POI, JXL等.

缺点则是, 会增加与服务器的交互, 如果采取前台获取数据传递给服务器的方式, 会产生巨大的开销.

2. ActiveXObject 与 execCommand

ActiveXObject 中可以使用例如 Excel.application 来创建 Excel 对象并保存之本地.

另一种方式则是通过 execCommand 的 SaveAs 参数进行文件的保存, 例如:

var doc = window.document;
doc.open('application/CSV','replace');
doc.charset = "utf-8";
doc.write("col1,col2");
doc.close();
doc.execCommand("SaveAs",null,"demo.csv")

以上两种方式均存在一个致命的缺点, 那就是只有 IE 支持, 所以对于开发来说帮助有限.

3. data 协议

这种方式通过指定一个资源的 data URI 来实现文件的导出下载功能.

function download(text, name) {
  var link = document.createElement("a");
  link.download = name;
  link.href = 'data:text/html,' + encodeURIComponent(text);
  link.click();
}
download("Hello, World!", "helloWorld.txt");

data协议的语法如下:

data:[sMediaType;][sBase64Encoding;],sResourceData

如果是指纯文本内容, 只需要把文本嵌入到 URI 中即可, 如:

var uri = 'data:,Hello%2C%20World!' //Hello, World

如果是其他类型文件, 则需要将文件内容转化为 Base64 格式, 可以通过一些开源的框架实现, 例如: js-base64, base64-js等, 或者利用 WindowBase64.btoa() 函数, 详细内容请参考MDN的文章.

4. HTML5

HTML5 中, 可以通过 window.URL.createObjectURL 方法来创建一个新的对象URL,该对象URL可以代表某一个指定的File对象或Blob对象.

var text = 'Hello, World!';
var MIME_TYPE = 'text/plain';

var downloadFile = function() {
  window.URL = window.webkitURL || window.URL;

  var bb = new Blob([text], {type: MIME_TYPE});

  var a = document.createElement('a');
  a.download = 'demo.txt';
  a.href = window.URL.createObjectURL(bb);
  a.textContent = 'Download ready';
  a.dataset.downloadurl = [MIME_TYPE, a.download, a.href].join(':');
  a.click();
};

downloadFile();

5. 开源框架

Downloadify:

//官方例子:
Downloadify.create('downloadify',{
  filename: function(){
    return document.getElementById('filename').value;
  },
  data: function(){
    return document.getElementById('data').value;
  },
  onComplete: function(){
    alert('Your File Has Been Saved!');
  },
  onCancel: function(){
    alert('You have cancelled the saving of this file.');
  },
  onError: function(){
    alert('You must put something in the File Contents or there will be nothing to save!');
  },
  transparent: false,
  swf: 'media/downloadify.swf',
  downloadImage: 'images/download.png',
  width: 100,
  height: 30,
  transparent: true,
  append: false
});

jsZip: jsZip 是一个用于创建, 读写 .zip 格式压缩文件的框架, 但是通过一些技巧, 例如: 构建 XML文件以及一些二进制文件, 生成Excel的压缩格式, 最终转换为Excel进行导出.

var fileName = 'demo.xls';
var zip           = new window.JSZip();
var _rels         = zip.folder("_rels");
var xl            = zip.folder("xl");
var xl_rels       = zip.folder("xl/_rels");
var xl_worksheets = zip.folder("xl/worksheets");

zip.file(           '[Content_Types].xml', excelStrings['[Content_Types].xml'] );
_rels.file(         '.rels',               excelStrings['_rels/.rels'] );
xl.file(            'workbook.xml',        excelStrings['xl/workbook.xml'] );
xl_rels.file(       'workbook.xml.rels',   excelStrings['xl/_rels/workbook.xml.rels'] );
xl_worksheets.file( 'sheet1.xml',          excelStrings['xl/worksheets/sheet1.xml'].replace( '__DATA__', xml ) );

var exeelURI = (window.URL || window.webkitURL || window).createObjectURL(blob);
window.open(exeelURI, "_blank");
comments powered by Disqus