使用Vue和JS下载CSV文件

12

我有一个名为csvdata的字段,其中包含以下格式的数组:

[
    [1,2,3],
    [4,5,6],
    [7,8,9]
]

我正在尝试下载这些数据的CSV文件。 我正在使用Vue,代码看起来像:

<button type="button" class="btn btn-info action_btn" v-on:click="downloadCSVData">
      Download
</button>

如何编写downloadCSVData函数?


你需要一个后端脚本语言,比如PHP,来将该数组处理成可下载的文件。 - Oliver M Grech
3个回答

27

假设csvdata是您的Vue组件中可访问的数据属性,我认为您可以创建以下方法:

downloadCSVData() => {
    let csv = 'Put,Column,Titles,Here\n';
    this.csvdata.forEach((row) => {
            csv += row.join(',');
            csv += "\n";
    });
 
    const anchor = document.createElement('a');
    anchor.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv);
    anchor.target = '_blank';
    anchor.download = 'nameYourFileHere.csv';
    anchor.click();
}


1
encodeURI 对于少量数据(约 2 行 8 列)有效。但是接下来使用 encodeURIComponent 可以处理更多的数据。 - Josh Morel
1
@JoshMorel 你说得对。我会更新我的答案。这里有一些关于它们之间区别的文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#encodeURI_vs_encodeURIComponent - j3py
优雅的解决方案 - 非常好 - Gene Bo
v-on 处理程序出错:"TypeError: row.join 不是一个函数"。 - Fernando Torres
@FernandoTorres 原帖中指出csvdata是一个二维数组。因此,每一行都是一个数组。在Javascript中,数组有一个内置方法叫做join。在这种情况下,row.join将起作用。如果csvdata是一个一维数组,那么每个“行”将是单个布尔值、字符串、数字或对象,它们都没有一个名为join的内置方法,因此你会得到你所描述的TypeError。 - j3py

2
以下是可以在Vue中下载CSV文件的工作代码:
这个示例代码将对象数组转换为带有标题的完美csv文件。调用函数exportCSVFile(headers, items, fileTitle)。
headers = { name: '姓名' // 格式化的列名称, age: '年龄' }
items = [ { name: 'Joo', age: 21 }, { name: 'ant', age: 20 } ]
filename = '一些文件名.csv'
function convertToCSV(objArray) {
  const array = typeof objArray !== 'object' ? JSON.parse(objArray) : objArray;
  let str = '';
  for (let i = 0; i < array.length; i++) { // eslint-disable-line
    let line = '';
    for (const index in array[i]) { // eslint-disable-line
      if (line !== '') line += ',';
      line += array[i][index];
    }
    str += line + '\r\n'; // eslint-disable-line
  }
  return str;
}

function exportCSVFile(headers, items, fileTitle) {
  if (headers) {
    items.unshift(headers);
  }
  const jsonObject = JSON.stringify(items);
  const csv = convertToCSV(jsonObject);
  const exportedFilenmae = fileTitle + '.csv' || 'export.csv'; // eslint-disable-line
  const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
  if (navigator.msSaveBlob) { // IE 10+
    navigator.msSaveBlob(blob, exportedFilenmae);
  } else {
    const link = document.createElement('a');
    if (link.download !== undefined) {
      const url = URL.createObjectURL(blob);
      link.setAttribute('href', url);
      link.setAttribute('download', exportedFilenmae);
      link.style.visibility = 'hidden';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }
  }
}

export default exportCSVFile;

如果给定的值是二维数组,只需使用此函数。
function downloadCSVData () {
    var array = [
    [1,2,3],
    [4,5,6],
    [7,8,9]
    ];
    var str = '';
    for (var i = 0; i < array.length; i++) { 
    let line = '';
    line = array[i].join(",");
    str += line + '\r\n';
    }
    var blob = new Blob([str], { type: 'text/csv;charset=utf-8;' });

    var link = document.createElement('a');
    var url = URL.createObjectURL(blob);
    link.setAttribute('href', url);
    link.setAttribute('download', 'csvfilename.csv');
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

1
  1. 将数组转换为文本。(let data = [[1,2,3], [4,5,6], [7,8,9]].join('\r\n').toString()
  2. 将文本转换为Base64格式。(let encoded_data = btoa(data)
  3. 创建一个iFrame并设置其src为编码后的数据。let iframe = document.createElement('iframe'); iframe.src = "data:application/octet-stream;base64," + encoded_data
  4. 将iFrame添加到文档的主体中:document.body.appendChild(iframe)

但是这种方法有一些缺点:

  1. 内容安全策略可能会阻止第四步。您可以在页面中控制CSP,但不要为了简化代码而牺牲安全性。
  2. 文件将始终以“download”命名,没有文件扩展名。

更好的方法是在服务器上创建临时文件并向用户提供该文件的链接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接