概要
DOM設計とは「HTMLを操作する」ことではない。
それは**構造・意味・操作・効率を統合する「UIの根幹設計」**である。
JavaScriptによってDOMを生成・制御する際、再描画、構造破壊、イベントの過剰結合といった問題が頻発する。
本稿では、それらを未然に防ぐための責任あるDOM設計戦略を提示する。
1. DOM構築は「意味単位」で行う
function createUserCard(user) {
const card = document.createElement('div');
card.className = 'user-card';
const name = document.createElement('h2');
name.textContent = user.name;
const email = document.createElement('p');
email.textContent = user.email;
card.append(name, email);
return card;
}
- ✅ 「UIパーツ」をコンポーネント関数で定義
- ✅ DOMの直接生成でも意味単位で分離する
2. 動的要素の責務を「構築・挿入・破棄」に分離
function insertUserList(users) {
const list = document.createElement('ul');
for (const user of users) {
const item = document.createElement('li');
item.textContent = user.name;
list.appendChild(item);
}
document.querySelector('#container').replaceChildren(list);
}
- ✅ 「生成」と「挿入」は別関数に → テストしやすくなる
- ✅
replaceChildren()
でフラッシュ的更新に
3. DOMイベント設計との分離
function bindButton(el, callback) {
el.addEventListener('click', callback);
}
- ✅ UI構築とイベント登録を分離して設計
- ✅ 複数イベント登録を構造化できる
function bindEvents(el, events) {
for (const [type, handler] of Object.entries(events)) {
el.addEventListener(type, handler);
}
}
4. パフォーマンス設計:再描画と再検索の最小化
- ✅ DOMツリー更新はまとめて1回
- ✅
DocumentFragment
を活用して仮想構築 → 挿入
const frag = document.createDocumentFragment();
for (const data of items) {
const el = document.createElement('li');
el.textContent = data;
frag.appendChild(el);
}
list.appendChild(frag);
5. 意味と構造の分離:データ属性の活用
<button data-user-id="u01">詳細</button>
btn.dataset.userId; // → "u01"
- ✅ DOMに意味を埋め込むのではなく、data- で分離*
- ✅ アプリ構造とUI構造の結合を緩やかに保てる
6. DOMの破棄とガーベジ設計
- ✅ 必ずイベントリスナーを解除する
function destroy(el) {
el.remove();
}
- ✅ Webアプリでは DOM残存 + イベント残存 → メモリリークを引き起こす
→ ✅ 「構築」「破棄」「再利用」のライフサイクル関数を分離して設計
設計判断フロー
① そのDOMは意味単位で構成されているか? → UI部品化へ
② DOMの構築とイベントが混在していないか? → 分離して責務明確化
③ 再描画を毎回DOMに適用していないか? → Fragment化 or replaceChildren
④ UIとロジックが結合していないか? → data-*で分離、ロジックは別層に
⑤ 破棄処理を忘れていないか? → destroy関数とremoveEventListener
よくあるミスと対策
❌ innerHTML +=
を多用して毎回再評価・再構築が発生
→ ✅ DOM APIを用いた構築と挿入に分離
❌ 1つの関数でDOM構築・挿入・イベント登録・削除まで一括処理
→ ✅ 責務ごとの分離によりテスト性と再利用性を向上
❌ 破棄したはずのDOMにイベントが残留
→ ✅ removeEventListener + remove() を忘れずに
結語
DOMとは「UIの器」ではない。
それは意味・操作・振る舞いの集合体であり、構造そのものである。
- 生成は意味単位にし
- 振る舞いは責務で分離し
- 表示は一括で最小化し
- 破棄まで設計する
JavaScriptにおけるDOM設計とは、
“UIの構造を保ち、意味を壊さず、振る舞いを統合する”という設計戦略である。