JavaScriptの多次元配列をHTMLテーブルで表示する練習
まずは「配列の配列」をテーブルに変換する感覚を掴みましょう。段階的に練習できるように、シンプル→応用の順で例を用意しました。
基本練習: 二次元配列をそのまま表にする
HTMLとJavaScriptだけで、多次元配列をテーブル化します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>配列→テーブル表示</title>
<style>
table { border-collapse: collapse; margin-top: 12px; }
th, td { border: 1px solid #999; padding: 6px 10px; text-align: left; }
caption { font-weight: bold; margin-bottom: 6px; }
</style>
</head>
<body>
<h1>多次元配列をHTMLテーブルに表示</h1>
<div id="app"></div>
<script>
// 練習用データ(行 = レコード、列 = 項目)
const data = [
["Yamada", 28, "Tokyo"],
["Suzuki", 35, "Fukuoka"],
["Honda", 24, "Sendai"]
];
// テーブル生成関数(見出しなし版)
function renderTable(containerId, rows) {
const container = document.getElementById(containerId);
const table = document.createElement('table');
// 各行と各セルを作成
rows.forEach(row => {
const tr = document.createElement('tr');
row.forEach(cell => {
const td = document.createElement('td');
td.textContent = cell;
tr.appendChild(td);
});
table.appendChild(tr);
});
container.appendChild(table);
}
renderTable('app', data);
</script>
</body>
</html>
HTML- 目的: 配列を二重のループでテーブルの行・列に変換する感覚を掴む。
- ポイント:
forEachで「行→セル」を順に作る。document.createElementとappendChildでDOMを積み上げる。
見出し付きテーブル: ヘッダー行を追加する
列名があるとグッと実用的になります。
<div id="app2"></div>
<script>
const headers = ["Name", "Age", "City"];
const rows = [
["Yamada", 28, "Tokyo"],
["Suzuki", 35, "Fukuoka"],
["Honda", 24, "Sendai"]
];
function renderTableWithHeader(containerId, headers, rows) {
const container = document.getElementById(containerId);
const table = document.createElement('table');
// キャプション(任意)
const caption = document.createElement('caption');
caption.textContent = "User list";
table.appendChild(caption);
// ヘッダー
const thead = document.createElement('thead');
const trHead = document.createElement('tr');
headers.forEach(h => {
const th = document.createElement('th');
th.textContent = h;
trHead.appendChild(th);
});
thead.appendChild(trHead);
table.appendChild(thead);
// 本体
const tbody = document.createElement('tbody');
rows.forEach(row => {
const tr = document.createElement('tr');
row.forEach(cell => {
const td = document.createElement('td');
td.textContent = cell;
tr.appendChild(td);
});
tbody.appendChild(tr);
});
table.appendChild(tbody);
container.appendChild(table);
}
renderTableWithHeader('app2', headers, rows);
</script>
HTML- 目的:
<thead>,<tbody>,<th>を使って構造化。 - ポイント: データの列順とヘッダーの整合性を保つ。
応用: オブジェクト配列から列選択して表示
よくある「オブジェクトの配列」から、必要なプロパティだけ列にします。
<div id="app3"></div>
<script>
const users = [
{ name: "Yamada", age: 28, city: "Tokyo", active: true },
{ name: "Suzuki", age: 35, city: "Fukuoka", active: false },
{ name: "Honda", age: 24, city: "Sendai", active: true }
];
// 表示する列を宣言的に定義
const columns = [
{ key: "name", label: "Name" },
{ key: "age", label: "Age" },
{ key: "city", label: "City" },
{ key: "active", label: "Active" }
];
function renderObjectTable(containerId, data, columns) {
const container = document.getElementById(containerId);
const table = document.createElement('table');
// ヘッダー
const thead = document.createElement('thead');
const trHead = document.createElement('tr');
columns.forEach(col => {
const th = document.createElement('th');
th.textContent = col.label;
trHead.appendChild(th);
});
thead.appendChild(trHead);
table.appendChild(thead);
// 本体
const tbody = document.createElement('tbody');
data.forEach(item => {
const tr = document.createElement('tr');
columns.forEach(col => {
const td = document.createElement('td');
td.textContent = item[col.key];
tr.appendChild(td);
});
tbody.appendChild(tr);
});
table.appendChild(tbody);
container.appendChild(table);
}
renderObjectTable('app3', users, columns);
</script>
HTML- 目的: 現実的なデータ構造をテーブルにマッピングする。
- ポイント: 列定義を配列にし、拡張しやすくする。
エラーハンドリング・不均一データへの備え
列数が揃っていない配列でも安全に描画します。
<div id="app4"></div>
<script>
const messy = [
["A", 1],
["B", 2, "extra"],
["C"] // 列不足
];
function renderSafeTable(containerId, rows) {
const container = document.getElementById(containerId);
const table = document.createElement('table');
// 最大列数を計算
const maxCols = rows.reduce((m, r) => Math.max(m, r.length), 0);
const tbody = document.createElement('tbody');
rows.forEach(row => {
const tr = document.createElement('tr');
for (let i = 0; i < maxCols; i++) {
const td = document.createElement('td');
td.textContent = row[i] !== undefined ? row[i] : ""; // 欠損は空表示
tr.appendChild(td);
}
tbody.appendChild(tr);
});
table.appendChild(tbody);
container.appendChild(table);
}
renderSafeTable('app4', messy);
</script>
HTML- 目的: 不揃いなデータでも崩れず表示。
- ポイント: 先に最大列数を測ってから各行を埋める。
スタイリングと小技
- 中央寄せ: 数値列だけ中央寄せなど、列に応じてクラスを付ける。
- 交互行: 視認性UPのためのストライプ表示。
- クリック操作: 行クリックで詳細表示や選択状態を切り替え。
/* 交互行 */
tbody tr:nth-child(odd) { background: #fafafa; }
/* 数値用 */
td.num { text-align: center; }
CSS// 数値列にクラス付与(例: 2列目と3列目)
columns.forEach((col, idx) => {
// 例:列定義にtypeを持たせて判定しても良い
});
JavaScript練習課題
- 合計列の追加: 点数表に「合計」と「平均」列を追加して表示する。
- ヒント:
row.slice(1)で点数部分を取り出し、reduceで合計を出す。
- ヒント:
- ソート機能: ヘッダーをクリックすると、その列で昇順/降順に並び替える。
- ヒント:
Array.prototype.sortを使い、クリック時に再描画。
- ヒント:
- フィルタリング: 入力欄で「City」に含まれる文字で絞り込み。
- ヒント:
includesで判定して、絞り込んだ配列を再表示。
- ヒント:
- 空値の表示ルール: 欠損データは「—」と表示して目立たせる。
- ヒント:
cell == null ? "—" : cellのように処理。
- ヒント:
つまづきポイントの回避策
- Label: 行と列のインデックスを混同しない
- 行が先、列が後。
data[rowIndex][colIndex]の順。
- 行が先、列が後。
- Label: DOMの再作成を忘れない
- 再描画時は、古いテーブルを消してから新しいテーブルを入れる。
- Label: データとヘッダーの列数整合性
- 列定義を1か所に集約し、コード重複を避ける。
