Javascript xlsx 套件練習
10 min readFeb 3, 2021
關鍵字: JS 讀取 excel,xls,xlsx,JS 寫入 excel,網頁讀寫 excel
最近用 JS + JQuery 幫 user 做完了一個需求,好處是 browser 自帶 UI 介面,不用在自己研究 GUI 要怎麼刻。
以下是個流程的介紹:
讀檔部分:
- <input id=”input_file_open” type=”file”/> 讀檔
- $(function() {}) 是 JQuery 寫法的 document ready,裡面負責處理各種 event(ex: onchange)
- 當點選 input buttom 後,會 call back 到 onchange(),會先做一些 init(ex: 清空 html 的一些元件),$(‘#[id]’) 是 JQuery 最實用的功能 - Selector,可以直接抓到 html dom 元件,不用再寫 getelementby(…)這麼落落長
- 可以從 event 取得 dom 的內容,並執行 list_sheets()
- FileReader() 可以 create reader,然後 call method 才會真的把 excel 內容讀出來,最後讀完才會 call back 到 onload(),真的很 call back 呢XD
- 一樣可以從 event 中得到 call back 的 input,把 excel 的內容傳給 show_sheets()
- XLSX.read() 可讀取 xlsx 格式的檔案
<!doctype html>
<html>
<head>
<title>JavaScript xlsx test</title>
<script src="bin/jquery-1.8.3.min.js"></script>
<script src="bin/xlsx-0.16.8.full.min.js"></script>
<script type="text/javascript">
var input_data;
function list_sheets(event) {
// Get The File From The Input
var input_file = event.target.files[0];
var reader = new FileReader(); // Ready The Event For When A File Gets Selected
reader.onload = function(e) {
input_data = e.target.result;
var wb = XLSX.read(data, {type: 'binary'});
show_sheets(wb);
}; // Tell JS To Start Reading The File.
// You could delay this if desired
reader.readAsBinaryString(input_file);
} // $(function() => JQuery 寫法的 document ready
$(function() {
var train_result_but = document.getElementById("input_file_open");
train_result_but.onchange = function(event) {
var fileData = event.target.files[0]; // 檔案資訊
if (fileData) {
if ($('#sheets_div').length)
$('#sheets_div').detach();
$('#file_name_p').text('輸入檔名: ' + fileData.name);
input_file_name = event.target.files[0];
list_sheets(event);
document.getElementById("input_file_open").value = "";
} else {
alert("輸入的檔案為無效檔案,請重新選取");
}
}
});
</script>
</head>
<body>
<label id="input_file_label">請選擇需檔案<br><br/>
<input id="input_file_open" type="file"/>
<p id="file_name_p"> </p>
<div id="sheets_div_root"></div>
</body>
</html>
列出 sheets:
- 利用 html() 在 sheets_div_root 底下長出 sheets_div,透過先埋好的 sheets_div_root 來決定物件長出的位置
- 可以從 wb.SheetNames 得到 sheet list,並將 checkbox value = sheet name
- 最後透過 append() 產生 checkbox 元件
- 另外,我還實作全選/全選取消的功能,方便使用者操作
- 最後透過 $(‘#[div] input:checked’)三個 selector 的組合技把選取的 checkbox 給挑出來
function show_sheets(wb) {
let item;
let sheets_div = '#sheets_div';
let select_all_but = '<input type="button" id="select_all_but" value="全選"><p><p/>';
let sheets_but = '<input type="button" id="sheets_submit" value="確認送出">'; if (!$(sheets_div).length)
$('#sheets_div_root').html('<div id="sheets_div"></div>'); /* Create sheet checkbox */
wb.SheetNames.forEach(function(sheetName) {
item = '<input type="checkbox" name="sheets[]" value="'+sheetName+'" /> \
<label for="A01">' + sheetName + '</label> <p><p/>'; // 這邊可以實作 checkbox onclick event
// item.onclcik = (e) => {
// console.log("checkbox: " + e.target.value + " is hit");
// };
$(sheets_div).append(item);
}); /* Create select all button(全選/全選取消) */
$(sheets_div).append(select_all_but);
let select_all_click = document.getElementById("select_all_but");
select_all_click.onclick = function() {
let arr = $("input[type='checkbox']");
let all_checked_flag = true;
Array.from(arr).forEach((i) => {
if (!i.checked)
all_checked_flag = false;
}); if (all_checked_flag)
Array.from(arr).forEach((i) => i.checked = false);
else
Array.from(arr).forEach((i) => i.checked = true);
} /* Create submit button */
$(sheets_div).append(sheets_but);let sheets_but_click = document.getElementById("sheets_submit");
sheets_but_click.onclick = function() {
var checked_l = [];
$('#sheets_div input:checked').each(function() {
checked_l.push($(this).attr('value'));
});
// 為啥以下寫法只會拿到"確認送出"?
// $('#sheets_div input:checked').each(() => checked_l.push($(this).attr('value'))); do_trans_result(checked_l);
}
}
送出 sheets:
- XLSX.utils.sheet_to_row_object_array() 可以轉換 sheet 內容成二維陣列
- XLSX.utils.aoa_to_sheet() 將二維陣列轉換成 sheet
- XLSX.utils.book_append_sheet() 將 sheet append 到 book 中
- XLSX.writeFile() output xlsx file
const OUTPUT_SHEETNAME = "Test Sheet";function do_feedback_result(feedback_sheet) {
/* Some business logic */
...
};function do_feedback_pick(sheet_l) {
var wb = XLSX.read(input_data, {type: 'binary'});
var output_wb = XLSX.utils.book_new(); sheet_l.forEach((sheet_name) => {
if (wb.SheetNames.includes(sheet_name)) {
let feedback_sheet = XLSX.utils.sheet_to_row_object_array(wb.Sheets[sheet_name]);
let output = do_feedback_result(feedback_sheet);
var ws = XLSX.utils.aoa_to_sheet(output);
XLSX.utils.book_append_sheet(output_wb, ws, OUTPUT_SHEETNAME);
}
}); XLSX.writeFile(output_wb, output_filename);
}function do_trans_result(checked_l) {
if (checked_l.length == 0)
return false; do_feedback_pick(checked_l);
}
ref:
[JQuery]
https://www.fooish.com/jquery/selectors.html
[checkbox]
https://www.tutorialrepublic.com/faq/how-to-check-a-checkbox-is-checked-or-not-using-jquery.php
https://stackoverflow.com/questions/2155622/get-a-list-of-checked-checkboxes-in-a-div-using-jquery