JavaScript:DOM操作(ブラウザで完結するUI作り)

投稿日:2026-01-13

音声

※ AI音声で読み上げます

目次

  1. querySelectorで要素を取る
  2. textContentとinnerHTML(安全な方を基本に)
  3. classListで見た目を切り替える
  4. data-*属性で要素に情報を持たせる
  5. 小さなrender関数で再描画する
  6. 注意(ここだけ)
  7. 要約

querySelectorで要素を取る

今回は、querySelectorやquerySelectorAllでHTML要素を選んで操作していきます。

querySelectorは、CSSセレクタの文字列を渡して、最初に見つかった**要素(Element)**を返します。idは#id、クラスは.classのように書きます。子孫セレクタや属性セレクタも使えます。

複数取りたい場合はquerySelectorAllでNodeListを取得してforEachで回すのが基本です。

DOMへアクセスするときは、スクリプトをbody末尾に置くかDOMContentLoadedで待つと安全です。

textContentとinnerHTML(安全な方を基本に)

textContentは文字列だけを安全に入れ替えますが、innerHTMLはHTMLをパースしてタグを反映します。

ユーザー入力や外部データを表示する際は、基本的にtextContentを使うのが安全です。

HTMLを使いたい場面は、静的で信頼できるテンプレートだけに限定するとよいです。

サニタイズ処理が必要なケースは後から検討しますが、まずはtextContentを既定にしてください。

classListで見た目を切り替える

classListは要素のクラス操作を簡潔にします。add/remove/toggle/containsがあり、toggleを使うとクリックで切り替えるUIが作りやすいです。

スタイルはCSS側にまとめておき、JSは状態(クラス)だけを切り替えると役割分担が明確になります。

複雑になったら状態名を定数化してミスを減らすことがポイントです。

data-*属性で要素に情報を持たせる

data-*属性は要素に小さなメタ情報を持たせるのに便利です。

datasetプロパティから読み書きでき、数値やIDなどをDOMに結びつけておくとイベントハンドラ側で扱いやすくなります。

サーバーから渡された識別子や、UIのモードなどを持たせる用途に向いています。

DOMとデータの簡単な紐付けに役立ちます。

小さなrender関数で再描画する

UI更新は小さなrender関数にまとめると、状態と表示の整合性が保ちやすくなります。状態(オブジェクトや配列)を更新したらrenderを呼び出してDOMをまとめて更新する設計がシンプルです。部分的に再描画する場合は、差分更新か必要な要素だけ書き換える工夫をするとパフォーマンスが安定します。少なくとも「状態を変更→render呼び出し」の流れを守ることをお勧めします。

貼り付け場所:CodePenを想定する場合はHTML欄にHTMLを、JS欄にJavaScriptを貼り付けてください。HTML欄にはボタン(#btn)や表示エリア(#out)を用意してあります。

最小コード:

<!-- HTML欄に貼る(CodePenのHTML欄) -->
<div id="app">
  <button id="btn">切替</button>
  <div id="out" data-count="0" class="box">カウント: 0</div>
</div>
/* CSS欄に貼る(CodePenのCSS欄) */
.box {
  padding: 12px;
  border: 2px solid #888;
  border-radius: 8px;
  display: inline-block;
  transition: 0.2s;
}

.box.active {
  background: #ffe08a;
  border-color: #ff9900;
  transform: scale(1.05);
  font-weight: bold;
}
// JS欄に貼る(CodePenのJS欄)
const btn = document.querySelector('#btn');
const out = document.querySelector('#out');

function render() {
  const count = Number(out.dataset.count);
  out.textContent = `カウント: ${count}`;
  out.classList.toggle('active', count % 2 === 1);
}

btn.addEventListener('click', () => {
  out.dataset.count = String(Number(out.dataset.count) + 1);
  render();
});

// 初期描画
render();

実行方法:CodePenでHTML欄とJS欄にそれぞれ上のコードを貼り、Run(自動実行が有効ならそのまま)でブラウザ上に表示します。もしローカルHTMLで試す場合は<script>をbody末尾に入れて開いてください。

確認方法:画面上の「切替」ボタンをクリックして表示(#out)の数字が増えることを確認し、奇数のときは見た目用のCSSクラス(active)でスタイルが変わることを目視します。Consoleに出すならrender内にconsole.logを追加して状態を確認できます。

よくあるミス:querySelectorで"#btn"などのセレクタが間違っているとnullになりaddEventListenerでエラーが出ます。解消法はまずConsoleでquerySelectorの結果を確認し、スクリプトをbody末尾に置くかDOMContentLoadedで待つようにすることです。

使い分けの基準:textContentはプレーンテキスト表示、innerHTMLは信頼できる静的テンプレート用に使い分けます。基本はtextContentを優先し、タグを入れる必要が明確で安全なケースのみinnerHTMLを選びます。

注意(ここだけ)

  • querySelectornull を返すと、その後の .textContent で落ちます。取得結果がある前提なら早めにチェックします。

  • 表示は基本 textContent を使い、innerHTML は最小限にします(意図しないHTML注入を防ぐ)。

  • DOMを何度も直接更新すると重くなりがちです。まず state を作り、最後にまとめて render する形が安定します。

要約

  • querySelector/querySelectorAllでCSSセレクタを使って要素を取得します。
  • 表示の置換は基本textContentを使い、HTMLが必要な場合のみinnerHTMLを限定して使います。
  • classListで見た目をクラス単位で切り替えると役割分担が明確になります。
  • data-*属性は要素に小さなデータを持たせるのに便利で、datasetから扱います。
  • 状態を更新したら小さなrender関数でDOMをまとめて再描画する設計が有効です。