【问题标题】:Export HTML table to CSV using vanilla javascript使用 vanilla javascript 将 HTML 表导出为 CSV
【发布时间】:2013-03-10 22:38:38
【问题描述】:

我正在尝试在我的网站中添加 csv 下载选项的功能。它应该将网站中存在的 html 表转换为 csv 内容并使其可下载。我一直在网上搜索一个好的插件,发现了一些有用的插件,比如http://www.dev-skills.com/export-html-table-to-csv-file/,但它使用 php 脚本来完成下载部分。我想知道是否有一个纯 javascript 库可用于使用 node.js 等服务器端软件而不使用 php 来执行此功能??

【问题讨论】:

标签: javascript jquery node.js html-table export-to-csv


【解决方案1】:

应该可以在每个现代浏览器上运行,并且没有 jQuery 或任何依赖项,这里是我的实现:

// Quick and simple export target #table_id into a csv
function download_table_as_csv(table_id, separator = ',') {
    // Select rows from table_id
    var rows = document.querySelectorAll('table#' + table_id + ' tr');
    // Construct csv
    var csv = [];
    for (var i = 0; i < rows.length; i++) {
        var row = [], cols = rows[i].querySelectorAll('td, th');
        for (var j = 0; j < cols.length; j++) {
            // Clean innertext to remove multiple spaces and jumpline (break csv)
            var data = cols[j].innerText.replace(/(\r\n|\n|\r)/gm, '').replace(/(\s\s)/gm, ' ')
            // Escape double-quote with double-double-quote (see https://stackoverflow.com/questions/17808511/properly-escape-a-double-quote-in-csv)
            data = data.replace(/"/g, '""');
            // Push escaped string
            row.push('"' + data + '"');
        }
        csv.push(row.join(separator));
    }
    var csv_string = csv.join('\n');
    // Download it
    var filename = 'export_' + table_id + '_' + new Date().toLocaleDateString() + '.csv';
    var link = document.createElement('a');
    link.style.display = 'none';
    link.setAttribute('target', '_blank');
    link.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv_string));
    link.setAttribute('download', filename);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

然后添加您的下载按钮/链接:

<a href="#" onclick="download_table_as_csv('my_id_table_to_export');">Download as CSV</a>

CSV 文件有时间并且与默认的 Excel 格式兼容。

cmets 后更新:添加了第二个参数“分隔符”,它可用于配置另一个字符,如 ;,如果您有用户在世界不同地区下载您的 csv,这很有用,因为他们可以为 Excel 使用另一个默认分隔符,有关详细信息,请参阅:https://superuser.com/a/606274/908273

【讨论】:

  • 太棒了!从 csv.push(row.join(';')); 更改一行后到 csv.push(row.join(','));,它对我有用。
  • 我只是在查找有关 Excel 默认分隔符的信息,它取决于区域,因此对于某些人来说确实有可能需要更改代码中的分隔符。请参阅:superuser.com/a/606274/908273
  • 很高兴找到@Calumah!谢谢。
  • 太好了。我想分号分隔符必须只是为了验证那些使用它的人不是彻头彻尾的蛞蝓。哈哈。无论如何,谢谢。
  • 我必须将 var rows = document.querySelectorAll('table#' + table_id + ' tr'); 更改为 var rows = document.querySelectorAll('#' + table_id + ' tr'); 才能正常工作,但现在一切正常
【解决方案2】:

仅使用 jQuery、原版 Javascripttable2CSV 库:

export-to-html-table-as-csv-file-using-jquery

将此代码放入要加载到head 部分的脚本中:

 $(document).ready(function () {
    $('table').each(function () {
        var $table = $(this);

        var $button = $("<button type='button'>");
        $button.text("Export to spreadsheet");
        $button.insertAfter($table);

        $button.click(function () {
            var csv = $table.table2CSV({
                delivery: 'value'
            });
            window.location.href = 'data:text/csv;charset=UTF-8,' 
            + encodeURIComponent(csv);
        });
    });
})

注意事项:

需要jQuerytable2CSV:在上述脚本之前添加对这两个库的脚本引用。

table 选择器为例,可以根据需要进行调整。

它仅适用于完全支持Data URI 的浏览器:Firefox、Chrome 和 Opera,不适用于 IE,IE 仅支持 Data URIs 将二进制图像数据嵌入页面。

为了完全兼容浏览器,您必须使用稍微不同的方法,该方法需要服务器端脚本来echo CSV。

【讨论】:

  • 嗨...感谢您的回答...但是当我尝试从您提供的链接下载 tabletoCsv 文件时...它显示错误“找不到页面”
  • 感谢您的回复!!!我真的很感谢你的帮助!!经过大量搜索datatables.net/examples,我也发现了另一个有趣的选择
  • 很高兴能帮到你。
  • 我已经尝试了上述大部分,但最简单的是这个。 jordiburgos.com/post/2014/…
  • 有什么方法可以设置文件名?
【解决方案3】:

http://jordiburgos.com/post/2014/excellentexport-javascript-export-to-excel-csv.html 有一个非常简单的免费和开源解决方案

首先从https://github.com/jmaister/excellentexport/releases/tag/v1.4下载javascript文件和示例文件

html 页面如下所示。

确保 javascript 文件在同一个文件夹中或相应地更改 html 文件中脚本的路径。

<html>
<head>
    <title>Export to excel test</title>
    <script src="excellentexport.js"></script>
    <style>
        table, tr, td {
            border: 1px black solid;
        }
    </style>
</head>
<body>
    <h1>ExcellentExport.js</h1>

    Check on <a href="http://jordiburgos.com">jordiburgos.com</a> and  <a href="https://github.com/jmaister/excellentexport">GitHub</a>.

    <h3>Test page</h3>

    <br/>

    <a download="somedata.xls" href="#" onclick="return ExcellentExport.excel(this, 'datatable', 'Sheet Name Here');">Export to Excel</a>
    <br/>

    <a download="somedata.csv" href="#" onclick="return ExcellentExport.csv(this, 'datatable');">Export to CSV</a>
    <br/>

    <table id="datatable">
        <tr>
            <th>Column 1</th>
            <th>Column "cool" 2</th>
            <th>Column 3</th>
        </tr>
        <tr>
            <td>100,111</td>
            <td>200</td>
            <td>300</td>
        </tr>
        <tr>
            <td>400</td>
            <td>500</td>
            <td>600</td>
        </tr>
        <tr>
            <td>Text</td>
            <td>More text</td>
            <td>Text with
                new line</td>
        </tr>
    </table>

</body>

因为我已经尝试了大多数其他方法,所以使用它非常容易。

【讨论】:

  • 可以用按钮代替锚点吗?
  • 我有一个使用 javascript 动态生成的表。显然,这个解决方案没有奏效。作为回报ExcellentExport.csv(this,'datatable'),'this'指的是什么?
【解决方案4】:

您不需要服务器端的 PHP 脚本。仅在客户端执行此操作,在接受 Data URIs 的浏览器中:

data:application/csv;charset=utf-8,content_encoded_as_url

数据 URI 将类似于:

data:application/csv;charset=utf-8,Col1%2CCol2%2CCol3%0AVal1%2CVal2%2CVal3%0AVal11%2CVal22%2CVal33%0AVal111%2CVal222%2CVal333

您可以通过以下方式调用此 URI:

  • 使用window.open
  • 或设置window.location
  • 或通过锚的href
  • 通过添加下载属性它可以在chrome中运行,仍然需要在IE中进行测试。

要进行测试,只需复制上面的 URI 并粘贴到浏览器地址栏中即可。或者在 HTML 页面中测试下面的锚点:

<a download="somedata.csv" href="data:application/csv;charset=utf-8,Col1%2CCol2%2CCol3%0AVal1%2CVal2%2CVal3%0AVal11%2CVal22%2CVal33%0AVal111%2CVal222%2CVal333">Example</a>

要创建内容,从表中获取值,您可以使用MelanciaUK 提到的table2CSV 并执行以下操作:

var csv = $table.table2CSV({delivery:'value'});
window.location.href = 'data:application/csv;charset=UTF-8,' + encodeURIComponent(csv);

【讨论】:

    【解决方案5】:

    (1)这是针对此问题的原生 javascript 解决方案。它适用于大多数现代浏览器。

    function export2csv() {
      let data = "";
      const tableData = [];
      const rows = document.querySelectorAll("table tr");
      for (const row of rows) {
        const rowData = [];
        for (const [index, column] of row.querySelectorAll("th, td").entries()) {
          // To retain the commas in the "Description" column, we can enclose those fields in quotation marks.
          if ((index + 1) % 3 === 0) {
            rowData.push('"' + column.innerText + '"');
          } else {
            rowData.push(column.innerText);
          }
        }
        tableData.push(rowData.join(","));
      }
      data += tableData.join("\n");
      const a = document.createElement("a");
      a.href = URL.createObjectURL(new Blob([data], { type: "text/csv" }));
      a.setAttribute("download", "data.csv");
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    }
    table {
      border-collapse: collapse;
    }
    
    td, th {
      border: 1px solid #aaa;
      padding: 0.5rem;
      text-align: left;
    }
    
    td {
      font-size: 0.875rem;
    }
    
    .btn-group {
      padding: 1rem 0;
    }
    
    button {
      background-color: #fff;
      border: 1px solid #000;
      margin-top: 0.5rem;
      border-radius: 3px;
      padding: 0.5rem 1rem;
      font-size: 1rem;
    }
    
    button:hover {
      cursor: pointer;
      background-color: #000;
      color: #fff;
    }
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Author</th>
          <th>Description</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>jQuery</td>
          <td>John Resig</td>
          <td>The Write Less, Do More, JavaScript Library.</td>
        </tr>
        <tr>
          <td>React</td>
          <td>Jordan Walke</td>
          <td>React makes it painless to create interactive UIs.</td>
        </tr>
        <tr>
          <td>Vue.js</td>
          <td>Yuxi You</td>
          <td>The Progressive JavaScript Framework.</td>
        </tr>
      </tbody>
    </table>
    
    <div class="btn-group">
      <button onclick="export2csv()">csv</button>
    </div>

    (2)如果你想要一个纯javascript库,FileSaver.js可以帮你保存触发文件下载的代码sn-ps。此外,FileSaver.js 将不负责构建要导出的内容。您必须以您想要的格式自己构建内容。

    【讨论】:

      【解决方案6】:

      使用了上面的答案,但根据我的需要进行了更改。

      我使用了以下函数并导入到我需要下载 csv 文件的 REACT 文件中。

      我的th 元素中有一个span 标签。将 cmets 添加到大多数函数/方法的功能中。

      import { tableToCSV, downloadCSV } from './../Helpers/exportToCSV';
      
      
      export function tableToCSV(){
        let tableHeaders = Array.from(document.querySelectorAll('th'))
          .map(item => {
            // title = splits elem tags on '\n',
            // then filter out blank "" that appears in array.
            // ex ["Timestamp", "[Full time]", ""]
            let title = item.innerText.split("\n").filter(str => (str !== 0)).join(" ")
            return title
          }).join(",")
      
        const rows = Array.from(document.querySelectorAll('tr'))
        .reduce((arr, currRow) => {
          // if tr tag contains th tag.
          // if null return array.
          if (currRow.querySelector('th')) return arr
      
          // concats individual cells into csv format row.
          const cells = Array.from(currRow.querySelectorAll('td'))
            .map(item => item.innerText)
            .join(',')
          return arr.concat([cells])
        }, [])
      
      return tableHeaders + '\n' + rows.join('\n')
      }
      
      export function downloadCSV(csv){
        const csvFile = new Blob([csv], { type: 'text/csv' })
        const downloadLink =  document.createElement('a')
        // sets the name for the download file
        downloadLink.download = `CSV-${currentDateUSWritten()}.csv`
        // sets the url to the window URL created from csv file above
        downloadLink.href = window.URL.createObjectURL(csvFile)
        // creates link, but does not display it.
        downloadLink.style.display = 'none'
        // add link to body so click function below works
        document.body.appendChild(downloadLink)
      
        downloadLink.click()
      }
      

      当用户点击导出到 csv 时,它会在 react 中触发以下功能。

        handleExport = (e) => {
          e.preventDefault();
          const csv = tableToCSV()
          return downloadCSV(csv)
        }
      

      示例 html 表格元素。

        <table id="datatable">
              <tbody>
                <tr id="tableHeader" className="t-header">
                  <th>Timestamp
                    <span className="block">full time</span></th>
                  <th>current rate
                    <span className="block">alt view</span>
                  </th>
                  <th>Battery Voltage
                    <span className="block">current voltage
                    </span>
                  </th>
                  <th>Temperature 1
                    <span className="block">[C]</span>
                  </th>
                  <th>Temperature 2
                    <span className="block">[C]</span>
                  </th>
                  <th>Time & Date </th>
                </tr>
      
              </tbody>
              <tbody>
                {this.renderData()}
              </tbody>
            </table>
          </div>
      

      【讨论】:

      • 感谢您写下这篇文章,您能否在 downloadCSV() 中添加您正在调用的函数 currentDateUSWritten()
      【解决方案7】:

      现代解决方案

      这里提出的大多数解决方案都会与嵌套表或 td 元素中的其他元素相冲突。我经常在表格中使用其他元素,但只想导出最顶层的表格。我从 Calumah 获取了一些在这里找到的代码,并添加了一些现代香草 ES6 JS。

      使用 textContent 是比 innerText 更好的解决方案,因为 innerText 将返回 td 元素内的任何 HTML。但是,即使 textContent 也会从嵌套元素返回文本。一个更好的解决方案是在您的 td 上使用自定义数据属性并从那里为您的 CSV 提取值。

      编码愉快!

      function downloadAsCSV(tableEle, separator = ','){
          let csvRows = []
          //only get direct children of the table in question (thead, tbody)
          Array.from(tableEle.children).forEach(function(node){
              //using scope to only get direct tr of node
              node.querySelectorAll(':scope > tr').forEach(function(tr){
                  let csvLine = []
                  //again scope to only get direct children
                  tr.querySelectorAll(':scope > td').forEach(function(td){
                      //clone as to not remove anything from original
                      let copytd = td.cloneNode(true)
                      let data
                      if(copytd.dataset.val) data = copytd.dataset.val.replace(/(\r\n|\n|\r)/gm, '')
                      else {
                          Array.from(copytd.children).forEach(function(remove){
                              //remove nested elements before getting text
                              remove.parentNode.removeChild(remove)   
                          })
                          data = copytd.textContent.replace(/(\r\n|\n|\r)/gm, '')
                      }
                      data = data.replace(/(\s\s)/gm, ' ').replace(/"/g, '""')
                      csvLine.push('"'+data+'"')
                  })
                  csvRows.push(csvLine.join(separator))
              })
          })
          var a = document.createElement("a")
          a.style = "display: none; visibility: hidden" //safari needs visibility hidden
          a.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csvRows.join('\n'))
          a.download = 'testfile.csv'
          document.body.appendChild(a)
          a.click()
          a.remove()
      }
      

      编辑:cloneNode() 更新为 cloneNode(true) 以获取内部信息

      【讨论】:

        【解决方案8】:

        我发现有一个图书馆。请参阅此处的示例:

        https://editor.datatables.net/examples/extensions/exportButtons.html

        除了上面的代码,还加载了以下Javascript库文件供本例使用:

        在 HTML 中,包含以下脚本:

        jquery.dataTables.min.js   
        dataTables.editor.min.js   
        dataTables.select.min.js
        dataTables.buttons.min.js  
        jszip.min.js    
        pdfmake.min.js
        vfs_fonts.js  
        buttons.html5.min.js    
        buttons.print.min.js
        

        通过添加如下脚本启用按钮:

        <script>
        $(document).ready( function () {
            $('#table-arrays').DataTable({
                dom: '<"top"Blf>rt<"bottom"ip>',
                buttons: ['copy', 'excel', 'csv', 'pdf', 'print'],
                select: true,
            });
        } );
        </script>
        

        由于某些原因,excel 导出导致文件损坏,但可以修复。或者,禁用 excel 并使用 csv 导出。

        【讨论】:

          【解决方案9】:

          我使用了上面发布的 Calumah 的函数,但我确实遇到了他的代码的问题。

          行用分号连接

          csv.push(row.join(';'));
          

          但生成的链接内容类型为“text/csv”

          也许在 Windows 中这不是问题,但在 Excel for Mac 中,这会引发问题。我将数组连接更改为逗号,效果很好。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-09-21
            • 1970-01-01
            • 2015-09-25
            • 2017-11-23
            • 1970-01-01
            • 2013-03-11
            • 1970-01-01
            • 2016-06-21
            相关资源
            最近更新 更多