Web端导出CSV

Web端导出CSV

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

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

参考资料:

 
 
标签:  javascript
13
0
(请您对文章做出评价)
« 上一篇: dojo/dom-style样式操作学习笔记
» 下一篇: dojo/dom-construct.toDom方法学习笔记
posted @  2015-09-25 01:02  木的树 阅读( 2335) 评论( 11编辑  收藏

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值