[JavaScript講座] DOM操作の基礎

当ページのリンクには広告が含まれています。
目次

DOMとは何か

HTML → DOMツリー

ブラウザは:

  1. HTMLを読み込む
  2. パースして「木構造(ツリー)」にする
  3. そのツリーを DOM(Document Object Model) として JavaScript から操作できるようにする

例として、HTML:

<body>
  <h1 id="title">こんにちは</h1>
  <p class="message">メッセージ</p>
</body>

DOMツリーのイメージ:

document
└─ html
   ├─ head
   └─ body
      ├─ h1#title
      └─ p.message

JavaScript からは document を起点にこのツリーにアクセスします。

Node / Element という概念

DOMの世界にはいろいろな「ノード」があります。

  • Node:DOMツリーの全ての要素の共通インターフェース
    • 要素ノード(element)
    • テキストノード(text)
    • コメントノード(comment)など
  • Element:HTMLタグに対応するノード(<div>, <p>, <span> など)

普段よく触るのは「要素ノード(Element)」です。

要素の取得:DOMクエリAPI

古いAPI

  • document.getElementById(id)
  • document.getElementsByClassName(className)
  • document.getElementsByTagName(tagName)

例:

const title = document.getElementById("title");
const messages = document.getElementsByClassName("message"); // HTMLCollection

これらは歴史的に存在していて、今も使われますが、
新しく覚えるなら querySelector / querySelectorAll を基本にすると楽です。

モダンなAPI:querySelector / querySelectorAll

// CSSセレクタで1つだけ取得(最初の1件)
const title = document.querySelector("#title");
const firstMessage = document.querySelector(".message");

// CSSセレクタで複数取得(すべて)
const items = document.querySelectorAll(".item"); // NodeList
  • 引数は CSSセレクタ(#id, .class, tag, 組み合わせなど)
  • querySelector:マッチする 最初の1件(なければ null
  • querySelectorAll:マッチする すべて(NodeList)

例:

const firstItem = document.querySelector("ul.list > li");
const buttons = document.querySelectorAll("button.primary");

NodeList と HTMLCollection と Array

  • querySelectorAll → NodeList(静的)
  • getElementsByClassName → HTMLCollection(ライブ)

ざっくり:

  • NodeList(静的):取得時点のスナップショット。後でDOMが変わっても勝手には更新されない。
  • HTMLCollection(ライブ):DOMが書き換わると中身も自動で変わることがある。

そしてどちらも Array ではない ので、mapfilter が直接は使えません。

const items = document.querySelectorAll(".item");

items.forEach(el => {
  console.log(el.textContent);
});

// Arrayメソッドを使いたければ明示的に変換
const arr = Array.from(items);
const texts = arr.map(el => el.textContent);

テキスト・HTMLの読み書き

textContent(基本はこちらを使用)

const title = document.querySelector("#title");

console.log(title.textContent); // 現在のテキスト
title.textContent = "新しいタイトル"; // テキストを置き換え
  • 子要素も含めた「テキストノードだけ」を扱うプロパティ
  • HTMLタグは解釈されず、ただの文字列として扱われる(安全)

innerHTML(HTMLごと書き換え)

const box = document.querySelector("#box");

box.innerHTML = "<strong>太字</strong>と<span>タグ</span>を含む内容";
  • 文字列として渡したHTMLをパースして、要素として差し込む
  • 強力だが、XSS(スクリプト混入)リスクがあるので、生のユーザー入力には使わない

ざっくり使い分け:

  • テキストだけ変えたい → textContent
  • 手元で安全に生成したHTML断片を入れたい → innerHTML もアリ

属性・値・データ属性

属性アクセス:id, href, src, value など

多くのHTML属性は、要素オブジェクトのプロパティとして直接操作できます。

<a id="link" href="https://example.com">Example</a>
<input id="nameInput" value="Taro" />
const link = document.querySelector("#link");
console.log(link.href);        // 絶対URLとして取得
link.href = "https://google.com";

const input = document.querySelector("#nameInput");
console.log(input.value);      // 入力値
input.value = "Hanako";        // 入力値を書き換え

getAttribute / setAttribute

属性名そのままを扱いたい場合は、こちら。

const link = document.querySelector("#link");

console.log(link.getAttribute("href")); // HTML上の値(相対パスなど)
link.setAttribute("href", "/home");

プロパティ vs attribute の違いは細かく言うと色々ありますが、
まずは:

  • 一般的な操作 → プロパティ(element.href, element.value
  • 「属性そのもの」を気にする特殊な場合 → getAttribute / setAttribute

くらいの認識でOKです。

データ属性と dataset

<div id="item" data-id="123" data-role="admin"></div>
const item = document.querySelector("#item");

console.log(item.dataset.id);   // "123"
console.log(item.dataset.role); // "admin"

// 書き換え
item.dataset.role = "user";
  • data-foo-bardataset.fooBar というキャメルケースでアクセス
  • 簡単なメタ情報・設定値を DOM に埋め込むのに便利

クラスとスタイルの操作

クラス操作:classList

<div id="box" class="box active"></div>
const box = document.querySelector("#box");

// クラスを追加
box.classList.add("highlight");

// クラスを削除
box.classList.remove("active");

// トグル(あれば消す・なければ追加)
box.classList.toggle("hidden");

// 所持確認
if (box.classList.contains("highlight")) {
  console.log("ハイライト中");
}

昔は element.className を文字列として扱っていましたが、
今は基本 classList を覚える方が圧倒的に楽&安全です。

インラインスタイル:style プロパティ

<div id="box"></div>
const box = document.querySelector("#box");

box.style.width = "200px";
box.style.backgroundColor = "red"; // CSSのbackground-color → JSではbackgroundColor

// まとめて指定するならstyle.cssTextもある
box.style.cssText = "width: 200px; height: 100px; background: blue;";
  • CSSの background-color → JSでは backgroundColor のようにキャメルケース
  • ただし レイアウト系はなるべくCSSで管理し、JSのstyle操作は必要最小限 がベター

要素の生成・挿入・削除

要素を新しく作る:document.createElement

const li = document.createElement("li");
li.textContent = "新しい項目";
li.classList.add("item");

挿入:append, prepend, before, after

<ul id="list">
  <li class="item">A</li>
</ul>
const list = document.querySelector("#list");
const li = document.createElement("li");
li.textContent = "B";

// 子要素の末尾に追加
list.append(li);

// 子要素の先頭に追加
// list.prepend(li);

// 兄弟として前後に追加
// list.before(li);
// list.after(li);
  • append / prepend は 子リスト に追加
  • before / after は 兄弟として 挿入
  • IE対応などが不要なら、この4つで大体足りることが多いです

従来の appendChild もまだよく使われますが、
モダンなブラウザ前提なら append の方が柔軟(文字列も渡せるなど)。

削除:remove

<div id="box"></div>
const box = document.querySelector("#box");
box.remove(); // 親から自分を削除

従来は parent.removeChild(child) でしたが、
今は child.remove() がシンプル。

innerHTML vs 明示的な構築

同じことをやる別のパターン:

list.innerHTML += '<li class="item">B</li>';
  • コードは短くなるが、
    • 中身が毎回全部パースされる(パフォーマンス面)
    • 既存のイベントリスナなどが消える場合もある
    • ユーザー入力をそのまま突っ込むと危険

なので、基本スタイルとしては:

  • 構造を組む → createElement + append など
  • innerHTML は「安全なテンプレート文字列からまとめて描画したいとき」に限定

くらいで考えておくとバランスがいいです。

親子・兄弟ノードの参照

DOM を辿りながら処理したい場面もあるので、代表的なプロパティを。

const item = document.querySelector(".item");

const parent = item.parentElement;         // 親要素
const children = parent.children;          // 子要素コレクション(HTMLCollection)
const first = parent.firstElementChild;    // 最初の子要素
const last = parent.lastElementChild;      // 最後の子要素

const prev = item.previousElementSibling;  // 前の兄弟要素
const next = item.nextElementSibling;      // 次の兄弟要素
  • parentNode / childNodes など「Nodeレベル」のプロパティもありますが、
    最初は Element系 (parentElement, children, ElementChild) を使う方が分かりやすいです。

<<前へ(async / await)

>>次へ(イベントとブラウザAPI)

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次