整個流程要用的的技術其實沒有太高深,但是陷阱卻是很多,因此整理成一篇備存。
(圖片出處: pexels.com)
一、需要解決的難題
1. JS 如何儲存 CSV
一開始需要瞭解如何將資料存成 CSV 檔,概念可參考這個討論串「How to export JavaScript array info to csv (on client side)?」:
- 在頁面製作一個超連結,而網址連結的字串可以設定成 CSV 這樣的型態
- 把所有資料格式整理好,用逗點分隔開,塞進 href 的值即可
- 使用者點擊連結後,就能存成 CSV 檔
2. 解決 UNICODE 亂碼問題
可惜這樣的 CSV 檔,用 EXCEL 開啟後,只要內容有中文(UNICODE)就會產生亂碼,原因可參考這篇「【Javascript】匯出 csv」。
利用這篇的技巧,在 CSV 檔開頭前幾個字元,塞入特定的編碼字串,可讓 CSV 檔成功在 EXCEL 顯示中文。
3. 資料太多時會被截斷
看完前面第一點的概念後,就知道存成 CSV 檔是靠網址傳值的概念。但客戶的會員資料起碼有幾萬筆,很快就超出瀏覽器網址字串限制的長度,所以無法成功儲存所有的會員資料為 CSV 檔。
這個討論串「Export HTML table to csv in google chrome browser」使用了不同的作法:
- 原本的作法藉著網址傳遞字串資料,會受到網址字串的長度限制。
- 新的作法將字串轉換為二進位資料(BLOB),依然用網址傳遞,但資料型態不同,就不會受到字串的長度限制。
- BLOB 格式的資料大小依然會有上限,但存成 CSV 檔的資料型態,要超出限制是極度困難的事情,所以除非資料多到像影片檔那麼大,那麼可不必擔心此事。
4. 依然是 UNICODE 亂碼問題
解決資料長度問題,改用 BLOB 格式後,又要再度面臨亂碼問題。
找到這篇「使用 JavaScript 导出 CSV 文件」,一樣在資料開始處加入特殊編碼字串,終於一切都正常了。
二、表格範例 + 匯出按鈕
- 以下範例表格內容,取自「利用 Google 試算表當小型資料庫 (4)使用 SQL 語法讓搜尋功能更強大」及本站會員系統
- 表格的美化使用「Bootstrap」內建的條紋換色效果
- 按下綠色按鈕,可匯出會員資料,存成 CSV 檔
匯出 WFU BLOG 會員資料
權限 | 序號 | 暱稱 | 性別 | 註冊日期 |
---|---|---|---|---|
加值會員 | W00001 | Wayne Fu | 男生 | 2014/9/12 |
一般會員 | W00002 | Che | 女生 | 2014/9/17 |
一般會員 | W00003 | Ken | 男生 | 2014/9/17 |
一般會員 | W00004 | Sun | 男生 | 2014/9/17 |
一般會員 | W00005 | Liu | 男生 | 2014/9/17 |
一般會員 | W00006 | Don | 男生 | 2014/9/18 |
一般會員 | W00007 | Cha | 女生 | 2014/9/18 |
一般會員 | W00008 | Tun | 女生 | 2014/9/18 |
一般會員 | W00009 | 陳 | 男生 | 2014/9/18 |
一般會員 | W00010 | HY | 男生 | 2014/9/18 |
一般會員 | W00011 | 美 | 女生 | 2014/9/18 |
一般會員 | W00012 | Kat | 女生 | 2014/9/19 |
一般會員 | W00013 | Mar | 男生 | 2014/9/19 |
一般會員 | W00014 | Wan | 男生 | 2014/9/20 |
一般會員 | W00015 | Bas | 女生 | 2014/9/20 |
一般會員 | W00016 | 莊 | 男生 | 2014/9/23 |
一般會員 | W00017 | 詹 | 女生 | 2014/9/23 |
一般會員 | W00018 | Li | 男生 | 2014/10/2 |
一般會員 | W00019 | 陳 | 女生 | 2014/10/2 |
一般會員 | W00020 | 淵 | 男生 | 2014/10/3 |
三、範例程式碼
以上效果的範例程式碼如下:
<script src='//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js'></script>
<link href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css' rel='stylesheet'></link>
<a id="exportBtn" class="btn btn-success" target="_blank" download="WFUBLOG-會員資料.csv">匯出 WFU BLOG 會員資料</a>
<br/><br/>
<style>
#member_list {white-space: nowrap;}
#member_list thead{background: #5893c8;color:#fff;}
</style>
<div id="member_list" class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>權限</th>
<th>序號</th>
<th>暱稱</th>
<th>性別</th>
<th>註冊日期</th>
</tr>
</thead>
<tbody>
<tr>
<td>加值會員</td>
<td>W00001</td>
<td>Wayne Fu</td>
<td>男生</td>
<td>2014/9/12</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00002</td>
<td>Che</td>
<td>女生</td>
<td>2014/9/17</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00003</td>
<td>Ken</td>
<td>男生</td>
<td>2014/9/17</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00004</td>
<td>Sun</td>
<td>男生</td>
<td>2014/9/17</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00005</td>
<td>Liu</td>
<td>男生</td>
<td>2014/9/17</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00006</td>
<td>Don</td>
<td>男生</td>
<td>2014/9/18</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00007</td>
<td>Cha</td>
<td>女生</td>
<td>2014/9/18</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00008</td>
<td>Tun</td>
<td>女生</td>
<td>2014/9/18</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00009</td>
<td>陳</td>
<td>男生</td>
<td>2014/9/18</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00010</td>
<td>HY</td>
<td>男生</td>
<td>2014/9/18</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00011</td>
<td>美</td>
<td>女生</td>
<td>2014/9/18</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00012</td>
<td>Kat</td>
<td>女生</td>
<td>2014/9/19</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00013</td>
<td>Mar</td>
<td>男生</td>
<td>2014/9/19</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00014</td>
<td>Wan</td>
<td>男生</td>
<td>2014/9/20</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00015</td>
<td>Bas</td>
<td>女生</td>
<td>2014/9/20</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00016</td>
<td>莊</td>
<td>男生</td>
<td>2014/9/23</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00017</td>
<td>詹</td>
<td>女生</td>
<td>2014/9/23</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00018</td>
<td>Li</td>
<td>男生</td>
<td>2014/10/2</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00019</td>
<td>陳</td>
<td>女生</td>
<td>2014/10/2</td>
</tr>
<tr>
<td>一般會員</td>
<td>W00020</td>
<td>淵</td>
<td>男生</td>
<td>2014/10/3</td>
</tr>
</tbody>
</table>
</div>
<script>
// 點擊匯出
$("#exportBtn").click(function() {
var csvList = [],
titleList = [],
memberContent = "",
csvContent;
// 取得標題
$("#member_list th").each(function() {
titleList.push(this.innerHTML);
});
csvList.push(titleList);
// 取得所有資料
$("#member_list tbody > tr").each(function() {
var regList = [];
$(this).children("td").each(function() {
regList.push(this.innerHTML);
});
csvList.push(regList);
});
// 產生 csv 內容
csvList.forEach(function(rowArray) {
var row = rowArray.join(",");
memberContent += row + "\r\n";
});
// 產生 csv Blob
csvContent = URL.createObjectURL(new Blob(["\uFEFF" + memberContent], {
type: 'text/csv;charset=utf-8;'
}));
// 產生 csv 連結
this.href = csvContent;
});
</script>
- 前 2 行綠字可參考「引用 jQuery 的注意事項」,檢查範本是否已安裝過 jQuery、Bootstrap,如果已經安裝過請刪除,以免重複安裝。
- 藍字可修改下載的檔名
- 如果熟悉 JS,可參考註釋內容自行修改
更多「表格」使用技巧:
那反過來用 JS 上傳 csv 成為 table 的方法呢?
回覆刪除管理
想請問是否能"制定"轉成csv檔的"欄位寬度"呢?
回覆刪除在網路上一直找不太到資料,
Suggest: dataTables
回覆刪除