この記事で学べること
  • DOMとは何か、ブラウザとHTMLの関係
  • 要素の取得方法(querySelector・getElementById等)
  • テキスト・HTMLの書き換え方法
  • クラス・属性の操作
  • 要素の動的な作成・追加・削除
  • イベントリスナーによるユーザー操作への対応
  • 実践:タブUIとモーダルの実装

DOMとは何か

DOM(Document Object Model)とは、HTMLドキュメントをプログラムから操作するための仕組みです。ブラウザはHTMLを読み込むと、内部的にツリー構造(DOMツリー)を構築します。JavaScriptはこのDOMツリーを通じて、ページ上の要素を取得・変更・追加・削除できます。

たとえば以下のHTMLがあるとします:

<div id="app">
  <h1 class="title">こんにちは</h1>
  <p>JavaScriptを学ぼう</p>
</div>

このHTMLはDOMツリーでは次のように表現されます:

  • document(ルート)
  •  └ html
  •   └ body
  •    └ div#app
  •     ├ h1.title(テキスト:「こんにちは」)
  •     └ p(テキスト:「JavaScriptを学ぼう」)

要素の取得方法

JavaScriptでDOM操作を始めるには、まず対象の要素を取得する必要があります。主な方法を紹介します。

querySelector / querySelectorAll

CSSセレクタと同じ書き方で要素を取得できる、最も汎用的な方法です。

// IDで取得
const app = document.querySelector('#app');

// クラスで取得
const title = document.querySelector('.title');

// タグで取得
const para = document.querySelector('p');

// 複数取得(NodeList)
const buttons = document.querySelectorAll('button');
buttons.forEach(btn => {
  console.log(btn.textContent);
});

getElementById / getElementsByClassName

古くからある取得方法ですが、今でも広く使われています。

// IDで1つ取得(高速)
const header = document.getElementById('header');

// クラス名で複数取得(HTMLCollection)
const items = document.getElementsByClassName('item');

// タグ名で複数取得
const links = document.getElementsByTagName('a');
💡 どれを使えばいい?
基本的には querySelector / querySelectorAll を使えばOKです。CSSと同じ記法なので直感的で、柔軟なセレクタが使えます。パフォーマンスが最優先の場合は getElementById の方が若干高速です。

要素の内容を変更する

取得した要素のテキストやHTMLを書き換えることができます。

textContent と innerHTML

const title = document.querySelector('.title');

// テキストだけを変更(安全)
title.textContent = '新しいタイトル';

// HTMLごと変更(XSSに注意)
title.innerHTML = '<strong>太字のタイトル</strong>';

// 現在のテキストを読み取る
console.log(title.textContent); // → 太字のタイトル(タグなし)
console.log(title.innerHTML);   // → <strong>太字のタイトル</strong>
⚠️ innerHTML使用時の注意
innerHTML にユーザー入力をそのまま挿入すると、XSS(クロスサイトスクリプティング)攻撃の脆弱性が生じます。ユーザー入力を扱う場合は textContent を使うか、適切なサニタイズ処理を行ってください。

クラスと属性の操作

classList によるクラス操作

要素のCSSクラスを動的に操作できます。スタイルの切り替えによく使われます。

const box = document.querySelector('.box');

// クラスを追加
box.classList.add('active');

// クラスを削除
box.classList.remove('hidden');

// クラスの有無を切り替え
box.classList.toggle('open');

// クラスが存在するか確認
if (box.classList.contains('active')) {
  console.log('アクティブです');
}

// 複数のクラスをまとめて追加
box.classList.add('visible', 'animated', 'fade-in');

属性(attribute)の操作

const img = document.querySelector('img');

// 属性を取得
const src = img.getAttribute('src');

// 属性を設定
img.setAttribute('alt', '説明文');

// 属性を削除
img.removeAttribute('data-old');

// data属性はdatasetで便利に操作
const card = document.querySelector('.card');
card.dataset.id = '42';        // data-id="42" をセット
console.log(card.dataset.id);  // → 42

スタイルの直接操作

const box = document.querySelector('.box');

// インラインスタイルを設定
box.style.backgroundColor = '#3fb950';
box.style.width = '200px';
box.style.display = 'none';  // 非表示

// 計算済みスタイルを取得(読み取り専用)
const computed = getComputedStyle(box);
console.log(computed.fontSize); // → '16px'

要素の作成・追加・削除

JavaScriptで新しいHTML要素を動的に生成してページに追加することができます。

// 1. 要素を作成
const newItem = document.createElement('li');
newItem.textContent = '新しいアイテム';
newItem.classList.add('item');

// 2. 親要素に追加(末尾)
const list = document.querySelector('ul');
list.appendChild(newItem);

// 3. 特定の位置に挿入(insertBefore)
const firstItem = list.firstElementChild;
list.insertBefore(newItem, firstItem); // 先頭に挿入

// 4. より柔軟なinsertAdjacentHTML
list.insertAdjacentHTML('beforeend', '<li class="item">末尾追加</li>');
list.insertAdjacentHTML('afterbegin', '<li class="item">先頭追加</li>');

// 5. 要素を削除
const oldItem = document.querySelector('.item.old');
oldItem.remove(); // 直接削除(モダンな方法)

テンプレートを使った効率的な生成

// データ配列からリストを一括生成
const fruits = ['りんご', 'バナナ', 'みかん'];
const ul = document.querySelector('#fruit-list');

// DocumentFragmentで一括追加(パフォーマンス向上)
const fragment = document.createDocumentFragment();
fruits.forEach(fruit => {
  const li = document.createElement('li');
  li.textContent = fruit;
  fragment.appendChild(li);
});
ul.appendChild(fragment); // 1回のDOM操作で全要素を追加

イベントリスナー

ユーザーのクリック、入力、マウス操作などに反応させるにはイベントリスナーを使います。

addEventListener の基本

const btn = document.querySelector('#myButton');

// クリックイベント
btn.addEventListener('click', function(event) {
  console.log('クリックされました!');
  console.log(event.target); // クリックされた要素
});

// アロー関数でも書ける
btn.addEventListener('click', (e) => {
  e.preventDefault(); // デフォルト動作を止める
  alert('ボタンがクリックされました');
});

// イベントリスナーを削除
const handler = () => console.log('実行');
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler);

主なイベント一覧

カテゴリイベント名説明
マウスclickクリック時
マウスdblclickダブルクリック時
マウスmouseover / mouseoutマウスが乗った/離れた
キーボードkeydown / keyupキーを押した/離した
フォームinput入力値が変わった時
フォームsubmitフォーム送信時
フォームchange値が変更・確定した時
ページDOMContentLoadedDOM構築完了時
ページload全リソース読み込み完了
スクロールscrollスクロール時

イベント委譲(Event Delegation)

動的に追加された要素にもイベントを適用するテクニックです。親要素にイベントを設定し、event.target で実際に操作された子要素を判定します。

// 親要素にイベントを設定
const list = document.querySelector('#list');

list.addEventListener('click', (e) => {
  // クリックされたのがliタグかチェック
  if (e.target.tagName === 'LI') {
    e.target.classList.toggle('completed');
  }
  
  // closest()でより柔軟に判定
  const item = e.target.closest('.item');
  if (item) {
    console.log('アイテム:', item.dataset.id);
  }
});

実践:タブUIの実装

学んだことを活かして、タブ切り替えUIを実装してみましょう。

<!-- HTML -->
<div class="tab-container">
  <div class="tab-buttons">
    <button class="tab-btn active" data-tab="tab1">タブ1</button>
    <button class="tab-btn" data-tab="tab2">タブ2</button>
    <button class="tab-btn" data-tab="tab3">タブ3</button>
  </div>
  <div id="tab1" class="tab-content active">タブ1のコンテンツ</div>
  <div id="tab2" class="tab-content">タブ2のコンテンツ</div>
  <div id="tab3" class="tab-content">タブ3のコンテンツ</div>
</div>
// JavaScript
const tabButtons = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');

tabButtons.forEach(btn => {
  btn.addEventListener('click', () => {
    // 全ボタンからactiveを外す
    tabButtons.forEach(b => b.classList.remove('active'));
    // 全コンテンツを非表示
    tabContents.forEach(c => c.classList.remove('active'));
    
    // クリックされたボタンをactiveに
    btn.classList.add('active');
    // 対応するコンテンツを表示
    document.getElementById(btn.dataset.tab).classList.add('active');
  });
});

実践:シンプルなモーダルの実装

クリックで開閉するモーダルダイアログを作ります。

<!-- HTML -->
<button id="open-modal">モーダルを開く</button>
<div id="modal" class="modal" style="display:none">
  <div class="modal-overlay"></div>
  <div class="modal-content">
    <h2>モーダルタイトル</h2>
    <p>モーダルの内容</p>
    <button id="close-modal">閉じる</button>
  </div>
</div>
// JavaScript
const modal = document.getElementById('modal');
const openBtn = document.getElementById('open-modal');
const closeBtn = document.getElementById('close-modal');
const overlay = modal.querySelector('.modal-overlay');

// モーダルを開く
openBtn.addEventListener('click', () => {
  modal.style.display = 'flex';
  document.body.style.overflow = 'hidden'; // 背景スクロール禁止
});

// モーダルを閉じる関数
function closeModal() {
  modal.style.display = 'none';
  document.body.style.overflow = '';
}

closeBtn.addEventListener('click', closeModal);

// オーバーレイクリックでも閉じる
overlay.addEventListener('click', closeModal);

// Escキーでも閉じる
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') closeModal();
});

まとめ

今回はJavaScript DOM操作の基礎を学びました。重要なポイントをまとめます:

  • 要素の取得querySelector / querySelectorAll がおすすめ
  • 内容の変更:テキストは textContent、HTMLは innerHTML(XSSに注意)
  • クラス操作classList.add/remove/toggle でスタイル切り替え
  • 要素の作成createElementappendChild の流れ
  • イベントaddEventListener でユーザー操作に反応
  • パフォーマンスDocumentFragment や イベント委譲で効率化

DOM操作はフロントエンド開発の基本中の基本です。Reactなどのフレームワークを使う場合でも、この知識は必ず役に立ちます。ぜひ実際にコードを書いて練習してみてください!