使用JavaScript 将Json数据导出CSV文件

原理

  • CSV文件格式单元格之间是通过,隔开的
  • CSV文件格式里,换行是通过\n实现的

从上面两条结论,我们只有把相应的数据转换成,\n就可以了。但其实真正的答案应该是把相应的数据转换成,\r\n
为什么会这样?且让我一一道来:
我们在编辑Excel文件时,当编辑完成当前单元格时,想要编辑下一行紧挨着的单元格,按一下Enter键就可以。而Enter键在js字符串中是用\r表示的。那是不是吧\n替换成\r就可以了呢?
其实不可以,因为涉及到操作系统的问题:

  • 在Windows系统中,标准模式采用的是\r\n匹配Enter
  • 在mac系统中,用\r匹配Enter
  • 在Linux系统中,用\n匹配Enter

所以,最最最最终终终的结论是:

  • 将相应的数据转换成,\r\n,即:名称,熟练\r\n张三,2
  • 由于单元格之间使用,隔开,所以不支持单元格的合并行、合并列,其实这句话有点多余,CSV格式的文件本身就不支持单元格的合并列和行

实现方式

在编写代码之前,我们先来看一下具体数据和样式。假如当前的JSON数据是这样的

[
    {name: '张三', amont: '323433.56', proportion: 33.4},
    {name: '李四', amont: '545234.43', proportion: 55.45}
]

数据报告展示样式如下:

姓名金额占比
张三323,433.5633.40%
李四545,234.4355.45%

那如何使得导出的数据与展示的保持一致呢?
答案是:

  • 把要展示的表头文字也进行处理
  • 遍历取对应的key值
  • 设置formatter回调处理的当前值的函数

由此我们得到如下代码:



var JSonToCSV = {
  /*
   * obj是一个对象,其中包含有:
   * ## data 是导出的具体数据
   * ## fileName 是导出时保存的文件名称 是string格式
   * ## showLabel 表示是否显示表头 默认显示 是布尔格式
   * ## columns 是表头对象,且title和key必须一一对应,包含有
        title:[], // 表头展示的文字
        key:[], // 获取数据的Key
        formatter: function() // 自定义设置当前数据的 传入(key, value)
   */
  setDataConver: function(obj) {
    var data = obj['data'],
        ShowLabel = typeof obj['showLabel'] === 'undefined' ? true : obj['showLabel'],
        fileName = (obj['fileName'] || 'UserExport') + '.csv',
        columns = obj['columns'] || {
            title: [],
            key: [],
            formatter: undefined
        };
    var ShowLabel = typeof ShowLabel === 'undefined' ? true : ShowLabel;
    var row = "", CSV = '', key;
    // 如果要现实表头文字
    if (ShowLabel) {
        // 如果有传入自定义的表头文字
        if (columns.title.length) {
            columns.title.map(function(n) {
                row += n + ',';
            });
        } else {
            // 如果没有,就直接取数据第一条的对象的属性
            for (key in data[0]) row += key + ',';
        }
        row = row.slice(0, -1); // 删除最后一个,号,即a,b, => a,b
        CSV += row + '\r\n'; // 添加换行符号
    }
    // 具体的数据处理
    data.map(function(n) {
        row = '';
        // 如果存在自定义key值
        if (columns.key.length) {
            columns.key.map(function(m) {
                row += '"' + (typeof columns.formatter === 'function' ? columns.formatter(m, n[m]) || n[m] : n[m]) + '",';
            });
        } else {
            for (key in n) {
                row += '"' + (typeof columns.formatter === 'function' ? columns.formatter(key, n[key]) || n[key] : n[key]) + '",';
            }
        }
        row.slice(0, row.length - 1); // 删除最后一个,
        CSV += row + '\r\n'; // 添加换行符号
    });
    if(!CSV) return;
    this.SaveAs(fileName, CSV);
  },
  SaveAs: function(fileName, csvData) {
    // console.log(fileName, csvData);
  }
};

然后我们分别测试了如下数据:

JSonToCSV.setDataConver({
  data: [
    {name: '张三', amont: '323433.56', proportion: 33.4},
    {name: '李四', amont: '545234.43', proportion: 55.45}
  ],
  fileName: 'test',
  columns: {
    title: ['姓名', '金额', '占比'],
    key: ['name', 'amont', 'proportion'],
    formatter: function(n, v) {
      if(n === 'amont' && !isNaN(Number(v))) {
        v = v + '';
        v = v.split('.');
        v[0] = v[0].replace(/(\d)(?=(?:\d{3})+$)/g, '$1,'); // 千分位的设置
         return v.join('.');
      }
      if(n === 'proportion') return v + '%';
    }
  }
});

到此,数据转换完毕

下载方式

由于浏览器之间的差异,尤其是IE,所以不同的浏览器下载的方式也不一样,如Chrome和Firefox都支持a标签设置download属性和href值,然后调用aclick方法即可下载,IE既不支持adownload属性也不允许调用aclick方法。代码如下:

var a = document.querySelector('a');
a.click(); // 在这里 IE是拒绝执行的,会提示权限问题

那么对于支持a的download属性的,直接设置download属性值和href值,具体代码如下:

Chrome、Firefox等浏览器的的下载方式
SaveAs: function(fileName, csvData) {
    var bw = this.browser();
    if(!bw['edge'] ||  !bw['ie']) {
      var alink = document.createElement("a");
      alink.id = "linkDwnldLink";
      alink.href = this.getDownloadUrl(csvData);
      document.body.appendChild(alink);
      var linkDom = document.getElementById('linkDwnldLink');
      linkDom.setAttribute('download', fileName);
      linkDom.click();
      document.body.removeChild(linkDom);
    }
  },
  getDownloadUrl: function(csvData) {
    var _utf = "\uFEFF"; // 为了使Excel以utf-8的编码模式,同时也是解决中文乱码的问题
    return 'data:attachment/csv;charset=utf-8,' + _utf + encodeURIComponent(csvData);
  },
  browser: function() {
    var Sys = {};
    var ua = navigator.userAgent.toLowerCase();
    var s;
    (s = ua.indexOf('edge') !== - 1 ? Sys.edge = 'edge' : ua.match(/rv:([\d.]+)\) like gecko/)) ? Sys.ie = s[1]:
        (s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] :
        (s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] :
        (s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] :
        (s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] :
        (s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] : 0;
    return Sys;
  }

虽然看起来是可以了,但还是有问题。什么问题呢?

就是当数据量大的时候,比如几千条甚至几万条,在数据转换的时候,href的数值自然也就长了。若是超过浏览器自身限制的最大长度,会导致下载失败。具体每个浏览器之前URL最大长度限制如下(HTTP协议并没有限制URL的长度):

浏览器最大长度(字符数)备注
IE2083如果超过这个数字,提交按钮没有任何反应
Firefox65,536-
Chrome8,182-
Safari80,000-
Opera190,000-

所以我们这里借助 Blob(Blob传送门)来将转换好的数据进行处理,代码如下:

getDownloadUrl: function(csvData) {
    var _utf = "\uFEFF"; // 为了使Excel以utf-8的编码模式,同时也是解决中文乱码的问题
    if (window.Blob && window.URL && window.URL.createObjectURL) {
        var csvData = new Blob([_utf + csvData], {
            type: 'text/csv'
        });
        return URL.createObjectURL(csvData);
    }
    // return 'data:attachment/csv;charset=utf-8,' + _utf + encodeURIComponent(csvData);
  }

我们在查看href值为:blob:http://127.0.0.1:3000/9715ca8a-bb9a-4b0c-8546-9bd13e8f0b69
这样不管几万条还是几十万条数据都可以下载的
这里涉及到的知识点:encodeURIComponentURL.createObjectURL
到这里,Chrome、Firefox等浏览器解决了。



来自https://segmentfault.com/a/1190000011389463l

作者: 随机



  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用以下步骤来将 JSON 数据导出CSV 文件: 1. 安装 `json2csv` 模块: ```bash npm install json2csv --save ``` 2. 在需要导出 CSV 文件的组件中引入 `json2csv` 模块: ```javascript import { json2csv } from 'json2csv'; ``` 3. 将 JSON 数据转换为 CSV 格式: ```javascript const fields = ['name', 'age', 'email']; // CSV 表头 const data = [ { name: '张三', age: 28, email: 'zhangsan@example.com' }, { name: '李四', age: 32, email: 'lisi@example.com' }, { name: '王五', age: 24, email: 'wangwu@example.com' } ]; // JSON 数据 const csv = json2csv({ fields, data }); ``` 4. 创建一个下载链接来下载 CSV 文件: ```javascript const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.setAttribute('href', url); link.setAttribute('download', 'data.csv'); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); ``` 完整代码如下: ```javascript <template> <div> <button @click="exportCsv">导出 CSV</button> </div> </template> <script> import { json2csv } from 'json2csv'; export default { methods: { exportCsv() { const fields = ['name', 'age', 'email']; // CSV 表头 const data = [ { name: '张三', age: 28, email: 'zhangsan@example.com' }, { name: '李四', age: 32, email: 'lisi@example.com' }, { name: '王五', age: 24, email: 'wangwu@example.com' } ]; // JSON 数据 const csv = json2csv({ fields, data }); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.setAttribute('href', url); link.setAttribute('download', 'data.csv'); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } }; </script> ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值