はじめに#
Webアプリケーションでは、ユーザーの操作に応じて画面の内容を動的に変更する場面が頻繁にあります。たとえば、ToDoリストに新しいタスクを追加したり、不要な項目を削除したり、既存のテキストを更新したりする機能は、DOM(Document Object Model)の操作によって実現されます。
本記事では、JavaScriptを使ってDOM要素を「追加」「削除」「変更」する基本的な方法を、初心者向けに具体的なコード例を交えて解説します。DOMの基本概念や要素の取得方法については、JavaScriptのDOMの基本と要素取得の方法で詳しく解説していますので、あわせてご覧ください。
DOM要素の追加#
createElementで要素を作成する#
新しいDOM要素を作成するには、document.createElement()メソッドを使用します。このメソッドは、指定したタグ名の新しい要素ノードを作成します。
1
2
3
4
5
6
7
8
|
// 新しいdiv要素を作成
const newDiv = document.createElement("div");
// 新しいp要素を作成
const newParagraph = document.createElement("p");
// 新しいbutton要素を作成
const newButton = document.createElement("button");
|
作成された要素はまだDOMツリーに追加されていないため、ページには表示されません。要素を画面に表示するには、後述するappendChildやappendなどのメソッドを使って、既存の要素に追加する必要があります。
要素にコンテンツや属性を設定する#
作成した要素にテキストや属性を設定するには、以下のプロパティやメソッドを使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// 新しい要素を作成
const card = document.createElement("div");
// クラスを設定
card.className = "card";
// または classList を使用
card.classList.add("card", "highlight");
// IDを設定
card.id = "user-card";
// カスタム属性を設定
card.setAttribute("data-user-id", "123");
// テキストコンテンツを設定
card.textContent = "ユーザー情報カード";
// スタイルを設定
card.style.backgroundColor = "#f0f0f0";
card.style.padding = "16px";
|
appendChildで子要素として追加する#
appendChild()メソッドは、指定した親要素の最後の子要素として新しい要素を追加します。
1
2
3
4
5
6
7
8
9
10
|
// 親要素を取得
const container = document.getElementById("container");
// 新しい要素を作成して設定
const newItem = document.createElement("p");
newItem.textContent = "新しい段落です";
newItem.className = "paragraph";
// 親要素の最後に追加
container.appendChild(newItem);
|
appendChildは追加した要素を戻り値として返すため、連鎖的に操作を行うことも可能です。
1
2
3
|
// 要素を作成して追加、そのまま変数に格納
const paragraph = document.body.appendChild(document.createElement("p"));
paragraph.textContent = "追加後に設定することも可能です";
|
appendで複数の要素やテキストを追加する#
append()メソッドは、appendChildより新しいAPIで、複数の要素やテキストを一度に追加できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
const list = document.getElementById("my-list");
// 複数の要素を一度に追加
const item1 = document.createElement("li");
item1.textContent = "項目1";
const item2 = document.createElement("li");
item2.textContent = "項目2";
const item3 = document.createElement("li");
item3.textContent = "項目3";
list.append(item1, item2, item3);
// テキストも直接追加できる
const paragraph = document.createElement("p");
paragraph.append("これは", document.createElement("strong"), "太字", "を含むテキストです");
|
appendChildとappendの違いを以下の表にまとめます。
| 特徴 |
appendChild |
append |
| 引数 |
Nodeのみ(1つ) |
Node または 文字列(複数可) |
| 戻り値 |
追加したNode |
undefined |
| 文字列の追加 |
不可(TextNodeが必要) |
可能 |
| ブラウザ対応 |
全ブラウザ |
IE非対応 |
prependで先頭に追加する#
prepend()メソッドは、親要素の最初の子要素として追加します。
1
2
3
4
5
6
7
8
|
const container = document.getElementById("container");
const notice = document.createElement("div");
notice.className = "notice";
notice.textContent = "重要なお知らせ";
// 先頭に追加
container.prepend(notice);
|
insertBeforeで特定の位置に挿入する#
insertBefore()メソッドは、指定した要素の直前に新しい要素を挿入します。
1
2
3
4
5
6
7
8
9
|
const list = document.getElementById("item-list");
const items = list.children;
// 新しい要素を作成
const newItem = document.createElement("li");
newItem.textContent = "挿入されたアイテム";
// 2番目の要素の前に挿入(インデックス1の前)
list.insertBefore(newItem, items[1]);
|
挿入位置の指定を視覚的に表すと以下のようになります。
graph LR
subgraph "挿入前"
A1[項目1] --> B1[項目2] --> C1[項目3]
end
subgraph "insertBefore items 1 後"
A2[項目1] --> N2[新しい項目] --> B2[項目2] --> C2[項目3]
end
style N2 fill:#4CAF50,color:#fffinsertAdjacentHTMLでHTMLを直接挿入する#
insertAdjacentHTML()メソッドは、HTML文字列を指定した位置に挿入します。要素を個別に作成する手間を省きたい場合に便利です。
1
2
3
4
|
const container = document.getElementById("container");
// HTML文字列を挿入
container.insertAdjacentHTML("beforeend", '<div class="card"><h3>タイトル</h3><p>説明文</p></div>');
|
insertAdjacentHTMLの第1引数には、挿入位置を指定する文字列を渡します。指定できる位置は以下の4つです。
1
2
3
4
5
6
7
|
<!-- beforebegin: 要素の直前(兄弟要素として) -->
<div id="target">
<!-- afterbegin: 要素内の最初(最初の子要素として) -->
既存のコンテンツ
<!-- beforeend: 要素内の最後(最後の子要素として) -->
</div>
<!-- afterend: 要素の直後(兄弟要素として) -->
|
具体的な使用例を見てみましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
const target = document.getElementById("target");
// 要素の直前に挿入
target.insertAdjacentHTML("beforebegin", "<p>要素の前に挿入</p>");
// 要素内の最初に挿入
target.insertAdjacentHTML("afterbegin", "<p>最初の子として挿入</p>");
// 要素内の最後に挿入
target.insertAdjacentHTML("beforeend", "<p>最後の子として挿入</p>");
// 要素の直後に挿入
target.insertAdjacentHTML("afterend", "<p>要素の後に挿入</p>");
|
insertAdjacentHTMLを使用する際は、ユーザー入力をそのまま挿入しないよう注意してください。XSS(クロスサイトスクリプティング)攻撃の脆弱性につながる可能性があります。
1
2
3
4
5
6
|
// 危険な例:ユーザー入力をそのまま挿入
const userInput = '<script>alert("XSS")</script>';
container.insertAdjacentHTML("beforeend", userInput); // 危険
// 安全な例:テキストとして挿入
container.insertAdjacentText("beforeend", userInput); // 安全
|
DOM要素の削除#
removeで要素を削除する#
remove()メソッドは、要素自身をDOMツリーから削除します。最もシンプルで直感的な削除方法です。
1
2
3
4
5
|
// 削除したい要素を取得
const element = document.getElementById("remove-target");
// 要素を削除
element.remove();
|
複数の要素を削除する場合は、querySelectorAllと組み合わせて使用します。
1
2
3
|
// すべての.ad-banner要素を削除
const adBanners = document.querySelectorAll(".ad-banner");
adBanners.forEach(banner => banner.remove());
|
removeChildで子要素を削除する#
removeChild()メソッドは、親要素から指定した子要素を削除します。削除した要素は戻り値として返されるため、再利用することも可能です。
1
2
3
4
5
6
|
const list = document.getElementById("item-list");
const firstItem = list.firstElementChild;
// 最初の子要素を削除
const removed = list.removeChild(firstItem);
console.log(removed); // 削除された要素(再利用可能)
|
すべての子要素を削除する場合は、以下のような方法があります。
1
2
3
4
5
6
7
8
9
10
11
12
|
const container = document.getElementById("container");
// 方法1: innerHTMLを空にする(最もシンプル)
container.innerHTML = "";
// 方法2: replaceChildrenを使用(引数なしで呼び出すとすべて削除)
container.replaceChildren();
// 方法3: whileループで1つずつ削除
while (container.firstChild) {
container.removeChild(container.firstChild);
}
|
削除時の注意点#
要素を削除する前に、その要素に紐づいたイベントリスナーの扱いを考慮する必要があります。
1
2
3
4
5
6
7
8
9
10
|
const button = document.getElementById("my-button");
// イベントリスナーを追加
button.addEventListener("click", handleClick);
// 要素を削除
button.remove();
// 削除後、イベントリスナーは自動的に無効になる
// ただし、参照が残っている場合はメモリリークの原因になりうる
|
DOM要素の変更#
textContentでテキストを変更する#
textContentプロパティを使用すると、要素内のテキストコンテンツを取得または設定できます。
1
2
3
4
5
6
7
|
const heading = document.getElementById("page-title");
// テキストを取得
console.log(heading.textContent); // "現在のタイトル"
// テキストを変更
heading.textContent = "新しいタイトル";
|
textContentは、HTMLタグを含む文字列を設定しても、そのままテキストとして表示されます(HTMLとして解釈されない)。これは意図しないXSS攻撃を防ぐ点で安全です。
1
2
3
4
5
|
const paragraph = document.getElementById("content");
// HTMLタグはエスケープされて表示される
paragraph.textContent = "<strong>太字</strong>";
// 画面には「<strong>太字</strong>」と表示される
|
innerHTMLでHTML構造を変更する#
innerHTMLプロパティを使用すると、要素内のHTML構造ごと取得または変更できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
const container = document.getElementById("container");
// HTML構造を取得
console.log(container.innerHTML);
// HTML構造を変更
container.innerHTML = `
<h2>セクションタイトル</h2>
<p>段落のテキストです。</p>
<ul>
<li>リスト項目1</li>
<li>リスト項目2</li>
</ul>
`;
|
innerHTMLを使う際は、XSS攻撃に注意が必要です。ユーザー入力を直接innerHTMLに設定しないでください。
1
2
3
4
5
6
|
// 危険な例
const userComment = '<img src="x" onerror="alert(\'XSS\')">';
container.innerHTML = userComment; // スクリプトが実行される可能性
// 安全な例:textContentを使用
container.textContent = userComment; // テキストとして表示される
|
textContentとinnerHTMLの使い分け#
両者の違いを理解し、適切に使い分けることが重要です。
| 特徴 |
textContent |
innerHTML |
| HTMLの解釈 |
しない(テキストとして扱う) |
する |
| XSSリスク |
低い |
高い(ユーザー入力に注意) |
| パフォーマンス |
高速 |
やや遅い(HTMLパース処理) |
| 用途 |
プレーンテキストの操作 |
HTML構造の操作 |
属性を変更する#
要素の属性を変更するには、setAttributeメソッドや直接プロパティを操作します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
const link = document.getElementById("my-link");
// href属性を変更
link.href = "https://example.com/new-page";
// または
link.setAttribute("href", "https://example.com/new-page");
// target属性を追加
link.setAttribute("target", "_blank");
// カスタムデータ属性を変更
link.dataset.category = "news"; // data-category="news"
// 属性を削除
link.removeAttribute("target");
|
クラスを変更する#
要素のクラスを操作するには、classListプロパティを使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
const element = document.getElementById("my-element");
// クラスを追加
element.classList.add("active");
// 複数のクラスを追加
element.classList.add("highlight", "important");
// クラスを削除
element.classList.remove("inactive");
// クラスの有無を切り替え
element.classList.toggle("visible"); // あれば削除、なければ追加
// クラスの存在確認
if (element.classList.contains("active")) {
console.log("activeクラスがあります");
}
// クラスを置換
element.classList.replace("old-class", "new-class");
|
replaceWithで要素を置換する#
replaceWith()メソッドは、要素自身を別の要素に置き換えます。
1
2
3
4
5
6
7
8
9
|
const oldElement = document.getElementById("old-content");
// 新しい要素を作成
const newElement = document.createElement("div");
newElement.id = "new-content";
newElement.textContent = "更新されたコンテンツ";
// 要素を置換
oldElement.replaceWith(newElement);
|
文字列を渡すこともできます。
1
2
3
4
|
const placeholder = document.getElementById("placeholder");
// テキストで置換
placeholder.replaceWith("プレースホルダーが置き換えられました");
|
実践的な使用例#
ToDoリストの実装#
学んだメソッドを組み合わせて、簡単なToDoリストを実装してみましょう。
1
2
3
4
5
|
<div id="todo-app">
<input type="text" id="todo-input" placeholder="タスクを入力">
<button id="add-btn">追加</button>
<ul id="todo-list"></ul>
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
const input = document.getElementById("todo-input");
const addBtn = document.getElementById("add-btn");
const todoList = document.getElementById("todo-list");
// タスクを追加する関数
function addTask() {
const taskText = input.value.trim();
if (taskText === "") return;
// リストアイテムを作成
const li = document.createElement("li");
li.className = "todo-item";
// タスクテキスト
const span = document.createElement("span");
span.textContent = taskText;
// 完了ボタン
const completeBtn = document.createElement("button");
completeBtn.textContent = "完了";
completeBtn.addEventListener("click", () => {
li.classList.toggle("completed");
});
// 削除ボタン
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "削除";
deleteBtn.addEventListener("click", () => {
li.remove();
});
// 要素を組み立てて追加
li.append(span, completeBtn, deleteBtn);
todoList.appendChild(li);
// 入力欄をクリア
input.value = "";
}
// ボタンクリックでタスク追加
addBtn.addEventListener("click", addTask);
// Enterキーでもタスク追加
input.addEventListener("keypress", (e) => {
if (e.key === "Enter") {
addTask();
}
});
|
動的なテーブル行の追加#
APIから取得したデータをテーブルに動的に追加する例を見てみましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
const tableBody = document.getElementById("user-table-body");
// ユーザーデータ(実際にはAPIから取得)
const users = [
{ id: 1, name: "山田太郎", email: "yamada@example.com" },
{ id: 2, name: "鈴木花子", email: "suzuki@example.com" },
{ id: 3, name: "佐藤次郎", email: "sato@example.com" }
];
// テーブル行を追加する関数
function renderUsers(users) {
// 既存の行をクリア
tableBody.innerHTML = "";
users.forEach(user => {
const row = document.createElement("tr");
row.dataset.userId = user.id;
row.innerHTML = `
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.email}</td>
<td>
<button class="edit-btn">編集</button>
<button class="delete-btn">削除</button>
</td>
`;
// 削除ボタンのイベントリスナー
const deleteBtn = row.querySelector(".delete-btn");
deleteBtn.addEventListener("click", () => {
row.remove();
});
tableBody.appendChild(row);
});
}
renderUsers(users);
|
DocumentFragmentによるパフォーマンス最適化#
大量の要素を追加する場合、DocumentFragmentを使用することでパフォーマンスを向上させることができます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
const list = document.getElementById("large-list");
// 1000個の要素を追加する例
const items = Array.from({ length: 1000 }, (_, i) => `項目 ${i + 1}`);
// DocumentFragmentを作成
const fragment = document.createDocumentFragment();
items.forEach(itemText => {
const li = document.createElement("li");
li.textContent = itemText;
fragment.appendChild(li);
});
// 一度にDOMに追加(再描画は1回だけ)
list.appendChild(fragment);
|
DocumentFragmentを使用しない場合、各要素の追加ごとにブラウザが再描画を行う可能性があります。DocumentFragmentにまとめてからDOMに追加することで、再描画の回数を1回に抑えることができます。
DOM操作メソッドの比較表#
本記事で紹介したメソッドを一覧表にまとめます。
| メソッド/プロパティ |
操作 |
説明 |
createElement |
追加 |
新しい要素を作成 |
appendChild |
追加 |
親要素の最後に子要素を追加 |
append |
追加 |
複数の要素やテキストを追加 |
prepend |
追加 |
親要素の先頭に追加 |
insertBefore |
追加 |
指定した要素の前に挿入 |
insertAdjacentHTML |
追加 |
HTML文字列を指定位置に挿入 |
remove |
削除 |
要素自身を削除 |
removeChild |
削除 |
子要素を削除 |
textContent |
変更 |
テキストを取得・設定 |
innerHTML |
変更 |
HTML構造を取得・設定 |
setAttribute |
変更 |
属性を設定 |
classList |
変更 |
クラスを操作 |
replaceWith |
変更 |
要素を別の要素に置換 |
まとめ#
本記事では、JavaScriptを使ったDOM要素の追加・削除・変更の基本的な方法を解説しました。
DOM操作の基本は以下の3つです。
- 追加:
createElementで要素を作成し、appendChildやappendでDOMツリーに追加する
- 削除:
removeで要素自身を削除するか、removeChildで親要素から子要素を削除する
- 変更:
textContentやinnerHTMLでコンテンツを変更し、classListやsetAttributeで属性を操作する
DOM操作を行う際は、セキュリティ(XSS対策)とパフォーマンス(再描画の最小化)を常に意識することが重要です。これらの基本を押さえておけば、動的なWebアプリケーションの開発に必要なスキルの土台が築けます。
参考リンク#