微信号:FrontDev

介绍:分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯

Web端导出CSV

2015-10-19 20:08 前端大全

(点击上方,可快速关注)


作者:木的树

网址:http://www.cnblogs.com/dojo-lzz/p/4837041.html


前端导出文件大部分还是通过服务器端的方式生成文件,然后传递到客户端。但很多情况下当我们导出CSV时并不需要后端参与,甚至没有后端。



做过WebGIS的同学经常会碰到这种场景,用户的兴趣点数据以csv文件形式上传到web应用中以表格形式展示,并可以编辑属性信息,编辑完成后需要将数据下载到本地。特别是对一些敏感数据,用户不希望传递到应用服务器端,整个过程完全在客户端进行。


上传过程我们暂且不讨论,只讨论生成CSV以及下载过程。


CSV的生成


问题一:如何分行分列?


思路:分行使用“\n”,分列使用”,”


var str = "col1,col2,col3\nvalue1,value2,value3";


实际应用中发现导出的csv用excel打开后,列可以分开但行无法分开。


解决方法是,将生成的csv字符串使用encodeURIComponent编码;但是IE8/9中不能使用encodeURIComponent,而是:’sep=,\r\n’ + str;


str = encodeURIComponent(str);


问题二:字段值中含有特殊符号影响csv文件的正确解读,如:“,”,”\n”


思路:将含有特殊符号的字段用双引号包装起来,如:a,b => “a,b”


var textField = '"';

if (value && /[,\r\n]/g.test(value)) {

value = textField + value + textField;

}


实际应用发现少考虑了一种情况,如果字段值中含有‘ ” ’这个符号,经过上方代码处理反而会出现问题:a”b => “a”b”。显然是语法错误。


解决方法是将”换成”",a”b => “a”"b”


var textField = '"';

if (value && /[",\r\n]/g.test(value)) {

value = textField + value.replace(/(")/g, '""') + textField;

}


在解决以上问题后生成CSV字符串代码如下


//data: 数据数组,每个元素都包含_outFields中指定的字段名

//_outFields: 字段名称数组

exports.createCSVStr = function(data, _outFields) {

var textField = '"';

var content = "";

var len = 0,

n = 0,

comma = "",

value = "";

try {

array.forEach(_outFields, function(_field) {

content = content + comma + _field;

comma = ",";

});


content = content + "\r\n";

len = data.length;

n = _outFields.length;

for (var i = 0; i < len; i++) {

comma = "";

for (var m = 0; m < n; m++) {

var _field = _outFields[m];

value = data[i][_field];

if (!value && typeof value !== "number") {

value = "";

}

if (value && /[",\r\n]/g.test(value)) {

value = textField + value.replace(/(")/g, '""') + textField;

}

content = content + comma + value;

comma = ",";

}

content = content + "\r\n";

}

} catch (err) {

console.error(err);

content = "";

}


return content;

};


问题三:如果字段中含有希伯来文、法语、德语等文字('éà; ça; 12\nà@€; çï; 13'),导出的csv文件在Excel中打开后,这些文字呈现出乱码


解决方法:严格来说这并不是csv文件的问题,而是Excel处理文件编码方式问题,Excel默认并不是以UTF-8来打开文件,所以在csv开头加入BOM,告诉Excel文件使用utf-8的编码方式。


var BOM = "\uFEFF";

var csvStr = BOM + csvStr;


实际应用中发现,这种处理方式在windows中的Excel中打开后可以正常显示,但在mac上的Excel无法正确显示。目前没有完全的解决方案,但mac中可以使用自带的Numbers软件打开,不会出现乱码问题。


CSV的下载方式


问题一:如何在解决不同浏览器中的下载问题?


思路:


IE10以下,利用execCommand方法来保存csv文件


var oWin = window.top.open("about:blank", "_blank");

oWin.document.write('sep=,\r\n' + text);

oWin.document.close();

oWin.document.execCommand('SaveAs', true, filename);

oWin.close();


在实际应用中浏览器会打开一个新窗口,并弹出保存文件对话框,而对话框中保存类型时,只有html和text两项可选,此时需要在文件名中手动加上“.csv”后缀


IE10以及Edge浏览器使用navigator.msSaveBlob(blob);虽然这些浏览器也支持上面的方法,但可以避免上面遇到的问题。


var BOM = "\uFEFF";

var csvData = new Blob([BOM + text], { type: 'text/csv' });

navigator.msSaveBlob(csvData, filename);


msSaveBlob是IE的私有方法,只有IE10及以上和Edge浏览器支持。


Firefox、Chrome、Safari浏览器中使用a标签,利用html5中增加的download属性来下载csv


var link = html.create("a", {

href: 'data:attachment/csv;charset=utf-8,' + BOM + encodeURIComponent(text),

target: '_blank',

download: filename

}, this.domNode);

if (has('safari')) {

// # First create an event

var click_ev = document.createEvent("MouseEvents");

// # initialize the event

click_ev.initEvent("click", true /* bubble */ , true /* cancelable */ );

// # trigger the evevnt/

link.dispatchEvent(click_ev);

} else {

link.click();

}


Safari中并不支持除了input外的元素直接调用click方法,所以我们利用自定义事件,模拟用户点击来下载文件。实际应用中发现,如果csv字符串太大,以上方式在下载csv时会导致浏览器崩溃。解决的方法是利用URL.createObjectURL(blob)创建一个连接给a标签。


_isIE11: function() {

var iev = 0;

var ieold = (/MSIE (\d+\.\d+);/.test(navigator.userAgent));

var trident = !!navigator.userAgent.match(/Trident\/7.0/);

var rv = navigator.userAgent.indexOf("rv:11.0");


if (ieold) {

iev = Number(RegExp.$1);

}

if (navigator.appVersion.indexOf("MSIE 10") !== -1) {

iev = 10;

}

if (trident && rv !== -1) {

iev = 11;

}


return iev === 11;

},


_isEdge: function() {

return /Edge\/12/.test(navigator.userAgent);

},


_getDownloadUrl: function(text) {

var BOM = "\uFEFF";

// Add BOM to text for open in excel correctly

if (window.Blob && window.URL && window.URL.createObjectURL) {

var csvData = new Blob([BOM + text], { type: 'text/csv' });

return URL.createObjectURL(csvData);

} else {

return 'data:attachment/csv;charset=utf-8,' + BOM + encodeURIComponent(text);

}

},


download: function(filename, text) {

if (has('ie') && has('ie') < 10) {

// has module unable identify ie11 and Edge

var oWin = window.top.open("about:blank", "_blank");

oWin.document.write('sep=,\r\n' + text);

oWin.document.close();

oWin.document.execCommand('SaveAs', true, filename);

oWin.close();

}else if (has("ie") === 10 || this._isIE11() || this._isEdge()) {

var BOM = "\uFEFF";

var csvData = new Blob([BOM + text], { type: 'text/csv' });

navigator.msSaveBlob(csvData, filename);

} else {

var link = html.create("a", {

href: this._getDownloadUrl(text),

target: '_blank',

download: filename

}, this.domNode);

if (has('safari')) {

// # First create an event

var click_ev = document.createEvent("MouseEvents");

// # initialize the event

click_ev.initEvent("click", true /* bubble */ , true /* cancelable */ );

// # trigger the evevnt/

link.dispatchEvent(click_ev);

} else {

link.click();

}


html.destroy(link);

}

}


参考资料:


  • https://github.com/DrPaulBrewer/html5csv

  • http://stackoverflow.com/questions/4639372/export-to-csv-in-jquery

  • http://stackoverflow.com/questions/15547198/export-html-table-to-csv

  • http://stackoverflow.com/questions/21342492/encoding-issues-for-utf8-csv-file-when-opening-excel-and-textedit

  • http://stackoverflow.com/questions/6588068/which-encoding-opens-csv-files-correctly-with-excel-on-both-mac-and-windows

  • http://stackoverflow.com/questions/6002256/is-it-possible-to-force-excel-recognize-utf-8-csv-files-automatically

  • http://stackoverflow.com/questions/19492846/javascript-to-csv-export-encoding-issue

  • https://github.com/b4stien/js-csv-encoding




前端大全

微信号:FrontDev

打造东半球最好的 前端技术 微信号

--------------------------------------

商务合作QQ:2302462408

投稿网址:top.jobbole.com

 
前端大全 更多文章 5个典型的JavaScript面试题(上) Limu:JavaScript的那些书 Web开发:我希望得到的编程学习路线图 JavaScript基础工具清单 常用排序算法之JavaScript实现
猜您喜欢 【干货】超级有用的9个PHP代码片段 这七种回归分析技术,学了不后悔~ Cherry 机械键盘、GitHub 官方 T 恤、IO币 12 点开抢!《开发者头条》 v2.4.0 来啦! 一张图告诉你2016央视春晚支付宝8亿现金红包时刻表 构造器与方法重载。