JavaScriptは年々進化しており、様々なことがクライアントサイドのJavaScriptでもできるようになっています。Tipsでは、Excelを出力することのできるExcelJSを使用して、ブラウザ側のhtmlとJavaScriptでExcelを操作/出力する方法をご紹介します。
はじめに
クライアントサイドでのExcel出力について、弊社テクニカルレポートに詳細がまとめられています。
こちらも参考ください。
https://www.migaro.co.jp/contents/support/technical_report_search/no16/tech/16_01_04.pdf
ExcelJSとは
ExcelJSはNode.jsで使用できるパッケージでnpm※1に公開されています。
このパッケージを使用すると、ExcelファイルをJavaScriptで簡単に操作することができます。Node.jsのパッケージですが、Browserify※2を使用することでNode.js環境だけではなく、ブラウザ側(クライアントサイドJavaScript)のみでも、ExcelJSを使用することができます。
※1. npmとは、npmはノードパッケージマネージャーの略で、パッケージ単位にまとめられた、JavaScriptの各種ライブラリの依存関係を管理してくれるシステムです。
Node.jsにはnpmが同梱されています。
※2.Browserifyとは、require等、Node.jsで使用する記述や、npmのパッケージをブラウザ側で利用できるようにするパッケージです。
ExcelJSの入手
npmからExcelJSを入手します。
npmが必要になるため、Node.jsの公式サイトからインストーラをダウンロードして、インストーラからNode.jsをインストールしてください。
Node.jsの公式サイト
◆Node.js
https://nodejs.org/ja/
インストール自体は、インストーラーを実行するだけのため、簡単に導入することができます。
インストーラにnpmも同梱されているため、同時にインストールされます。
npmからExcelJSパッケージの入手
今回ブラウザ側で使用する、ExcelJSのJavaScriptファイルを入手します。
npmからダウンロードするExcelJSのパッケージには、browserifyでまとめられたJavaScriptファイルが含まれています。
クライアントサイド(ブラウザ側)でExcelJSを使用する場合には、browserifyでまとめられたJavaScriptファイル(dist/exceljs.js)を使用します。
npmの実行

コマンドプロンプトを起動後、npmと入力してください。
コマンドの使用方法が画面に表示されれば、npmが導入されています。
Tipsでは、Node.jsを使用せず、ExcelJSのパッケージをダウンロードするためにnpmを使用しますので、ファイルをダウンロードするフォルダへ、カレントディレクトリを設定してください。
例) C:\temp\js\

次に、以下のコマンドでパッケージを取得します。
npm install exceljs
カレントディレクトリにたくさんのファイルがダウンロードされますが、ブラウザ側で使用するJavaScriptファイルは一つです。
ExcelJSはパッケージにブラウザ側で使用するため、Browserifyが適用されたexceljs.jsファイルが含まれています。
node_modules/exceljs/dist/exceljs.min.js を取得してサーバーに配置ください。
Tipsでは、HTMLと同階層にjsフォルダを作成して配置しました。

JavaScriptでExcel出力
Tipsでは、Webサーバー上に配置したExcelファイルをテンプレートとして、ブラウザ側のJavaScriptでテンプレートのExcelファイルを読込み、読込んだExcelファイルにSmartPad4iで出力したテーブルデータを、ExcelJSで書込む手順をご紹介します。
テンプレートのExcelファイル作成
テンプレートのExcelファイルを作成します。
Tipでは、Excelで以下画像のようなExcelファイルをtemplate.xlsxという名前で作成しました。
作成した、template.xlsxはアプリのhtmlと同階層の配置しています。

ExcelJSの設定
ExcelJSを使用するために、HTML側に外部スクリプトの読込みを追加します。
polyfill.jsはブラウザの仕様の違いを吸収するためのJavaScriptになります。
外部読込みのScriptはhtml内のどこに追加しても動作しますが、</body>前に記述することをお勧めします。
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.26.0/polyfill.js"></script>
<script src="../../../smartpad4i/html/SP4IREP21/js/exceljs.js"></script>
HTMLの編集 テーブルタグの設定
テーブルのデータを取得するため、タグにカスタムデータ属性を追加します。
以前のTipsと同じでテーブルタグにカスタムデータ属性を追加しています。
https://www.migaro.co.jp/tips/1375/#toc4
Excelダウンロードボタンの配置
Excelのダウンロード用のボタンを追加します。
例では、アンカータグを使用しています。

カスタムデータ属性でdata-exceldownload=”true”を設定することでJavaScriptからボタンが認識できるようにしています。
<a class="button is-info load-b ml-1" data-exceldownload="true" >
<i class="fa fa-file-excel"></i>Excel</a>
ExcelJSによる出力
出力実行時の動画は以下になります。
ボタンクリック時にExcelファイルを出力します。
JavaScriptの例は以下です。
// ボタンクリック時の処理
$('[data-exceldownload]').on('click',function(){
createExcel();
});
// テンプレートのExcelファイルパス
const EXCEL_URL = '/smartpad4i/html/SP4IREP21/template.xlsx';
// 非同期関数
async function createExcel(){
// テンプレートのExcelファイルを読込み、バイト配列で取得
const existingExcelBytes = await fetch(EXCEL_URL).then(res => res.arrayBuffer());
// バイト配列で取得したExcelファイルを8ビット符号なし整数値の配列に変換
const exceldata = new Uint8Array(existingExcelBytes);
// ExcelBookの作成
const workbook = new ExcelJS.Workbook();
// テンプレートのExcelファイルのデータを読込み
await workbook.xlsx.load(exceldata);
// テーブルのデータ取得 data配列にデータを取得
let id_arr = $.makeArray($('[data-dwn-field="userid"]'));
let name_arr = $.makeArray($('[data-dwn-field="username"]'));
let dep_arr = $.makeArray($('[data-dwn-field="userdep"]'));
let auth_arr = $.makeArray($('[data-dwn-field="userauth"]'));
let date_arr = $.makeArray($('[data-dwn-field="userdate"]'));
let data = [];
let loopCount = $('[data-dwn-field="userid"]').length;
for(var i = 0 ; i < loopCount ; i++){
var rec = {};
rec.id = id_arr[i].innerText;
rec.name = name_arr[i].innerText;
rec.dep = dep_arr[i].innerText;
rec.auth = auth_arr[i].innerText;
rec.date = date_arr[i].innerText;
data.push(rec);
}
// テンプレートで設定したシート取得
const worksheet = workbook.getWorksheet('UserList');
// シートの用紙サイズ、縦横設定
worksheet.pageSetup = { paperSize: 9, orientation:'portrait'};
// データを書込む起点設定
const startRow = 4;
const startCol = 2;
let row = {};
let rownum = 0;
// Excelの開始行をデータの数コピー
worksheet.duplicateRow(startRow , data.length - 1 , false);
// シートに書き込み
for (const rec of data) {
let pos = startRow + rownum;
row = worksheet.getRow(pos);
console.log(rec);
row.getCell(startCol).value = rec.id;
row.getCell(startCol + 1).value = rec.name;
row.getCell(startCol + 2).value = rec.dep;
row.getCell(startCol + 3).value = rec.auth;
row.getCell(startCol + 4).value = rec.date;
rownum++;
}
// 書込みした内容をwriteBufferメソッドで出力
const uint8Array = await workbook.xlsx.writeBuffer();
// Blobオブジェクトの作成
const blob = new Blob([uint8Array], {type: 'application/octet-binary'});
// ダウンロードするためにblobのURL作成
const url = window.URL.createObjectURL(blob);
// アンカーを作成してURL設定
const a = document.createElement('a');
a.href = url;
// ダウンロードするファイル名を指定してダウンロード
a.download = 'ユーザー一覧.xlsx';
a.click();
a.remove();
}
ボタンクリック時の処理
// ボタンクリック時の処理
$('[data-exceldownload]').on('click',function(){
createExcel();
});
Excelをダウンロードするボタンには、カスタム属性 data-exceldownload を設定しています。
ボタンクリック時に非同期関数として定義したcreateExcelを呼び出してExcelを出力します。
非同期関数とawait
// 非同期関数
async function createExcel(){
非同期関数は処理に時間がかかる処理の場合等に定義します。
functionの前にasyncを記述するだけです。
また、非同期関数内部でのみ、await が使用できます。
awaitを使用することで、処理の終了を待機(同期的に処理)することができます。
テンプレートの読込み
// テンプレートのExcelファイルを読込み、バイト配列で取得
const existingExcelBytes = await fetch(EXCEL_URL).then(res => res.arrayBuffer());
// バイト配列で取得したExcelファイルを8ビット符号なし整数値の配列に変換
const exceldata = new Uint8Array(existingExcelBytes);
// ExcelBookの作成
const workbook = new ExcelJS.Workbook();
// テンプレートのExcelファイルのデータを読込み
await workbook.xlsx.load(exceldata);
EXCEL_URLには、Webサーバー上に配置したテンプレートのExcelファイル(template.xlsx)のパスが設定されています。
fetchはHTTPリクエストを送信するAPIです。
HTTPリクエストの処理はサーバーへのリクエスト処理後、HTTPレスポンスを取得するまでに時間が掛かる場合があります。
awaitを設定して呼び出すことで、HTTPレスポンスが返却されるまでの処理を同期的に実行できます。
アロー関数
「=>」の記述は アロー関数と呼ばれる記述です。
res => res.arrayBuffer()
簡単な例としては、上記の記述は以下と同じです。
function(res){
res.arrayBuffer();
}
Excelの作成
resにHTTPレスポンスが返却されるため、arrayBufferメソッドでバイナリデータを取得します。
取得したバイナリデータはUint8Arrayを使用して、JavaScriptで扱いやすいデータに変更しています。
// ExcelBookの作成
const workbook = new ExcelJS.Workbook();
// テンプレートのExcelファイルのデータを読込み
await workbook.xlsx.load(exceldata);
Excelの作成は、ExcelJSのWorkbookメソッドで行えます。
workbookを作成後、ファイルのI/O処理を行うオブジェクトxlsxのloadメソッドでworkbookに読込ます。
テーブルに出力されたデータの読込み
// テーブルのデータ取得 data配列にデータを取得
let id_arr = $.makeArray($('[data-dwn-field="userid"]'));
let name_arr = $.makeArray($('[data-dwn-field="username"]'));
let dep_arr = $.makeArray($('[data-dwn-field="userdep"]'));
let auth_arr = $.makeArray($('[data-dwn-field="userauth"]'));
let date_arr = $.makeArray($('[data-dwn-field="userdate"]'));
let data = [];
let loopCount = $('[data-dwn-field="userid"]').length;
for(var i = 0 ; i < loopCount ; i++){
var rec = {};
rec.id = id_arr[i].innerText;
rec.name = name_arr[i].innerText;
rec.dep = dep_arr[i].innerText;
rec.auth = auth_arr[i].innerText;
rec.date = date_arr[i].innerText;
data.push(rec);
}
テーブルの各列には、カスタムデータ属性を設定しています。
カスタムデータ属性を使用して、配列データを取得後、recオブジェクトをdata配列に追加していきます。
行のコピー処理
// テンプレートで設定したシート取得
const worksheet = workbook.getWorksheet('UserList');
// シートの用紙サイズ、縦横設定
worksheet.pageSetup = { paperSize: 9, orientation:'portrait'};
// データを書込む起点設定
const startRow = 4;
const startCol = 2;
let row = {};
let rownum = 0;
// Excelの開始行をデータの数コピー
worksheet.duplicateRow(startRow , data.length - 1 , false);
workbookに読み込んだExcelファイルから、getWorksheetメソッドを使用して、シートのデータを取得します。
worksheetオブジェクトのpageSetupメソッドで、用紙サイズ(paperSize)と縦横(orientation)を指定しています。
用紙サイズは以下URLのExample Paper size を確認してください。
https://github.com/exceljs/exceljs#page-setup

次に、worksheet内のduplicateRowメソッドを実行することで、シートの4行目をデータ分下行にコピーしています。
上記画像のように、枠線がデータ行数分コピーされます。
ワークシートへの書込み
// シートに書き込み
for (const rec of data) {
let pos = startRow + rownum;
row = worksheet.getRow(pos);
console.log(rec);
row.getCell(startCol).value = rec.id;
row.getCell(startCol + 1).value = rec.name;
row.getCell(startCol + 2).value = rec.dep;
row.getCell(startCol + 3).value = rec.auth;
row.getCell(startCol + 4).value = rec.date;
rownum++;
}
data配列に格納されたデータをループ処理で取り出します。
worksheetのgetRowメソッドを使用して行のオブジェクトを取得後、getCellメソッドで列番号のセルを取得して値を書き換えます。
xlsxファイルを作成してダウンロード
// 書込みした内容をwriteBufferメソッドで出力
const uint8Array = await workbook.xlsx.writeBuffer();
// Blobオブジェクトの作成
const blob = new Blob([uint8Array], {type: 'application/octet-binary'});
// ダウンロードするためにblobのURL作成
const url = window.URL.createObjectURL(blob);
// アンカーを作成してURL設定
const a = document.createElement('a');
a.href = url;
// ダウンロードするファイル名を指定してダウンロード
a.download = 'ユーザー一覧.xlsx';
a.click();
a.remove();
workbookのxlsxオブジェクトのwriteBufferメソッドで、unit8Array形式のデータが取得できます。
BlobオブジェクトにUint8Arrayを渡してblobオブジェクトを作成します。
次に、ダウンロードをするために、window.URL.createObjectURLメソッドでURLを取得して、アンカータグのhrefプロパティに設定して、アンカーのdownloadプロパティにダウンロードのファイル名を指定後クリックすることでファイルをダウンロードします。
以上で、Excel出力のためのJavaScript説明は終了です。
おわりに
JavaScriptの進化によって、ブラウザ側(クライアントサイド)のJavaScriptのみで、Excelファイルの操作/出力ができるようになりました。
SmartPad4i / Cobos4i のアプリケーションでExcel帳票を作成するような場合に是非ご活用ください。