簡體   English   中英

使用 vanilla javascript 將 HTML 表導出到 CSV

[英]Export HTML table to CSV using vanilla javascript

我正在嘗試在我的網站中添加 csv 下載選項的功能。 它應該將網站中的 html 表轉換為 csv 內容並使其可下載。 我一直在互聯網上搜索一個好的插件,發現了一些有用的插件,比如http://www.dev-skills.com/export-html-table-to-csv-file/但它使用 php 腳本來完成下載部分。 我想知道是否有一個純 javascript 庫可以使用服務器端軟件(如 node.js)來執行此功能,而無需使用 php?

應該適用於所有現代瀏覽器,無需 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 格式兼容。

評論后更新:添加了第二個參數“分隔符”,它可以用來配置另一個字符,如; ,如果您有用戶在世界不同地區下載您的 csv 很有用,因為他們可以使用 Excel 的另一個默認分隔符,有關更多信息,請參閱: https : //superuser.com/a/606274/908273

僅使用jQuery 、vanilla Javascripttable2CSV庫:

導出到 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,后者僅支持將二進制圖像數據嵌入頁面的Data URIs

為了完全兼容瀏覽器,您必須使用稍微不同的方法,該方法需要服務器端腳本echo顯 CSV。

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>

使用它非常容易,因為我已經嘗試了大多數其他方法。

您不需要服務器端的 PHP 腳本。 僅在客戶端執行此操作,在接受數據 URI 的瀏覽器中:

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

(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可以幫你保存觸發文件下載的代碼片段。 此外,FileSaver.js 將不負責構建導出內容。 您必須以您想要的格式自行構建內容。

使用了上面的答案,但根據我的需要對其進行了更改。

我使用了以下函數並導入到我需要下載 csv 文件的REACT文件中。

我的th元素中有一個span標簽。 添加了對大多數函數/方法所做的評論。

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 時,它會在反應中觸發以下功能。

  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>

我發現有一個圖書館。 請參閱此處的示例:

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 導出。

現代解決方案

此處提出的大多數解決方案都會與 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) 以獲取內部信息

我使用了上面發布的 Calumah 的函數,但我確實遇到了他的代碼問題。

行用分號連接

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

但生成的鏈接的內容類型為“text/csv”

也許在 Windows 中這不是問題,但在 Mac 版 Excel 中可能會出現問題。 我將數組連接更改為逗號,並且效果很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM