前端导出文件大部分还是通过服务器端的方式生成文件,然后传递到客户端。但很多情况下当我们导出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标签。

    _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);
    }
    },

  综合上述方式,下载csv文件的代码如下

    _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);
}
}

  如果您觉得这篇文章对您有帮助,请不吝点击下方推荐,您的鼓励是我分享的动力!

参考资料:

 
 

Web端导出CSV的更多相关文章

  1. web前端导出csv文件

    前言 导出文件,使用最多的方式还是服务器端来处理.比如jsp 中使用response 的方式. 但是,有时候可能就想使用web 前端是否也可以把页面上的内容导出来呢? 比如说,导出页面的一个表格. 这 ...

  2. .net web端导出Excel个人的看法

    //对已有方法进行重写 public override void VerifyRenderingInServerForm(Control control) { } //设置文件名 string fil ...

  3. Web 端 js 导出csv文件(使用a标签)

    前言 导出文件,使用最多的方式还是服务器端来处理.比如jsp 中使用response 的方式. 但是,有时候可能就想使用web 前端是否也可以把页面上的内容导出来呢? 比如说,导出页面的一个表格. 这 ...

  4. C#导出csv文件 支持中文的解决方案

    #region 导出CSV下载 string exportFileName = "Export" + DateTime.Now.ToString("yyyyMMddHHm ...

  5. ngTbale假分页实现排序、搜索、导出CSV等功能

    一. ngTable功能简化 使用ngTable经常有分页,排序,过滤等功能,实现诸多功能较为麻烦.为了方便开发过程,可以抽取一些table共同点写一个公有方法. 注意: 1. 由于很多特别的需求,可 ...

  6. 用NPOI实现导入导出csv、xls、xlsx数据功能

    用NPOI实现导入导出csv.xls.xlsx数据功能   直接上代码 首先定义一个接口   如果需要直接操作文件的话,就自己在封装一次 然后定义csv类的具体实现 这个需要引入命名空间LumenWo ...

  7. C#导出.csv格式的excel表

    .cs文件直接贴代码: using System; using System.Collections.Generic; using System.Data; using System.IO; usin ...

  8. web端权限维持【好文】

    前言 关于权限维持,我之前写过一篇基于系统端的后门技术文章,如映像劫持啊,lpk之类. 内容目录: - 构造文件包含漏洞- 隐蔽性脚本木马- 构造sql注入点 正文 0x01 构造文件包含漏洞 > ...

  9. Yearning v1.3.0 发布,Web 端 SQL 审核平台

    企业级MYSQL web端 SQL审核平台. Website 官网 www.yearning.io Feature 功能 数据库字典自动生成 SQL查询 查询工单 导出 自动补全,智能提示 查询语句审 ...

随机推荐

  1. 4. Prototype(原型)

    意图: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 适用性: 当要实例化的类是在运行时刻指定时,例如,通过动态装载:或者 为了避免创建一个与产品类层次平行的工厂类层次时:或者 当 ...

  2. PHP 汉字转拼音类

    本文转载自:http://www.epubit.com.cn/article/867 <?php function Pinyin($_String, $_Code='gb2312') { $_D ...

  3. 实战录 | 一起唠唠那些常见的DDoS攻击

    <实战录>导语 云端卫士<实战录>栏目定期会向粉丝朋友们分享一些在开发运维中的经验和技巧,希望对于关注我们的朋友有所裨益.本期分享人为云端卫士系统架构师高鹏,将带来常见的DDo ...

  4. 20145202、20145225、20145234 《信息安全系统设计基础》实验五 简单嵌入式WEB 服务器实验

    实验内容 1.配置环境 2.使用vi 编辑器阅读理解源码 2.编译应用程序 运行 make 产生可执行文件httpd 3.下载调试 使用 NFS 服务方式将HTTPD 下载到开发板上,并拷贝测试用的网 ...

  5. SQL查询符合条件的记录的总数

    1. select count(*) from table;    //统计元组个数 2. select count(列名) from table;  //统计一列中值的个数 3. select co ...

  6. mysq安装以及修改密码

    安装版MySQL是不能一键安装的,下载下来是压缩包,解压后只要进行相关配置就可以正常使用: 文章主要是记录一下,以防自己忘记: 1.首先在mysql官网--http://dev.mysql.com/d ...

  7. C#之方法的重载与递归

    (1). 方法的重载:方法的名称相同,但参数不同. 1.如果参数的个数相同,那么参数的类型不能相同. 2.如果参数的类型相同,那么参数的个数不能相同. (2).方法的递归:方法自己调用自己.用于找出一 ...

  8. 轮播神器swiper插件

    Swiper中文网:http://www.swiper.com.cn/ Swiper- 是免费的,最现代化的移动触摸滑块硬件加速的转换和惊人的天然行为.它的目的是在移动网站,移动网络应用和移动本地/混 ...

  9. ASP.NET MVC 部署全站HTTPS

    什么是全站HTTPS 全站HTTPS就是指整个网站的所有页面,所有资源全部使用HTTPS链接. 当用户的某个请求是明文的HTTP时,应该通过HTTP状态码301永久重定向到对应的HTTPS链接. 为了 ...

  10. 数学工具WZgrapher

    之前说了mathGV,其实还有一个不错类似软件WZgrapher,不仅可以画函数图,还可以微积分. 截图如下: