Javascript xlsx 套件練習

starzodiac
10 min readFeb 3, 2021

--

關鍵字: JS 讀取 excel,xls,xlsx,JS 寫入 excel,網頁讀寫 excel

最近用 JS + JQuery 幫 user 做完了一個需求,好處是 browser 自帶 UI 介面,不用在自己研究 GUI 要怎麼刻。

以下是個流程的介紹:

讀檔部分:

  1. <input id=”input_file_open” type=”file”/> 讀檔
  2. $(function() {}) 是 JQuery 寫法的 document ready,裡面負責處理各種 event(ex: onchange)
  3. 當點選 input buttom 後,會 call back 到 onchange(),會先做一些 init(ex: 清空 html 的一些元件),$(‘#[id]’) 是 JQuery 最實用的功能 - Selector,可以直接抓到 html dom 元件,不用再寫 getelementby(…)這麼落落長
  4. 可以從 event 取得 dom 的內容,並執行 list_sheets()
  5. FileReader() 可以 create reader,然後 call method 才會真的把 excel 內容讀出來,最後讀完才會 call back 到 onload(),真的很 call back 呢XD
  6. 一樣可以從 event 中得到 call back 的 input,把 excel 的內容傳給 show_sheets()
  7. 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:

  1. 利用 html() 在 sheets_div_root 底下長出 sheets_div,透過先埋好的 sheets_div_root 來決定物件長出的位置
  2. 可以從 wb.SheetNames 得到 sheet list,並將 checkbox value = sheet name
  3. 最後透過 append() 產生 checkbox 元件
  4. 另外,我還實作全選/全選取消的功能,方便使用者操作
  5. 最後透過 $(‘#[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:

  1. XLSX.utils.sheet_to_row_object_array() 可以轉換 sheet 內容成二維陣列
  2. XLSX.utils.aoa_to_sheet() 將二維陣列轉換成 sheet
  3. XLSX.utils.book_append_sheet() 將 sheet append 到 book 中
  4. 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

--

--

No responses yet