JavaScriptのDOM操作入門|要素取得・イベント・表示更新を練習する
※本記事にはPRを含む場合があります。
こんにちは。『脱会社員』脱サラを応援し続けるブログ、運営者の『なかびー』です。
JavaScriptで画面の文字を変えたり、ボタンに反応させたりするときに使うのがDOM操作です。基本は「対象を取得する」「出来事を受け取る」「必要な部分を更新する」の順で考えることです。動かないときも、この三段階に分ければ、要素が見つからないのか、イベントが届かないのか、更新の方法が違うのかを調べやすくなります。
この記事では、HTMLとCSS、JavaScriptの変数や関数を少し学んだ方向けに、小さな学習チェックリストを作ります。項目の追加、完了状態の変更、削除、件数の更新を一つの例で練習します。データを外部へ送る機能や、再読み込み後まで保存する機能は含みません。機密情報を入れず、練習用の短い言葉で試してください。
2026年10月3日にMDNのDOM、要素取得、イベント、文字更新の資料を確認しました。コードは本記事用の独自学習例で、本番サービスへそのまま導入する完成品ではありません。図版は説明用の生成イメージです。実行結果の画面や、特定環境での表示検証を示すものではありません。
DOM操作の入口|HTMLの構造とブラウザー内の要素

DOMはブラウザーが扱う文書の構造
ブラウザーはHTMLを読み、文書の要素や文字を構造として扱います。DOMでは、文書、要素、テキストなどをノードとして捉え、親子の関係をたどったり、内容を変更したりできます。HTMLファイルへ書いた文字列そのものと、ブラウザー内で現在できている構造は分けて考えましょう。JavaScriptで追加した要素は、元のHTMLファイルを書き換えなくても画面へ現れます。
たとえば、ulの中にliがあり、その中にチェックボックスと文字があるなら、一覧、項目、操作部品という関係になります。一覧へ項目を追加するときはulを取得し、新しく作ったliを入れます。項目だけ削除するときは、そのliを対象にします。どの範囲へ操作を行うかを決めるために、HTMLの入れ子が重要になります。
MDNのDOMスクリプティング入門は、文書の構造を取得して変更する基本を説明しています。最初は大きなサイト全体を対象にせず、自分で用意した見出し、段落、ボタンだけのページで試します。変更前のHTMLを理解している方が、何が変わったかを確認しやすくなります。
documentと要素の範囲を区別する
documentは現在の文書を扱う入口として使います。document.querySelectorで文書全体から対象を探す方法があり、取得した要素に対してquerySelectorを使えば、その範囲の中から探せます。一覧が複数あるページでは、先に対象の一覧を取得し、その中の項目を探すと、別の部品へ誤って作用することを減らせます。
DOM操作のコードは、ブラウザーなどDOMを提供する環境で動かす必要があります。JavaScriptという言語が動くすべての場所に、同じdocumentがあるわけではありません。ブラウザー用コードを別の実行環境で動かし、documentが見つからないと言われた場合は、構文だけでなく実行場所を確認します。HTMLへ読み込むコードと、サーバーで動くコードの役割を混同しないようにしましょう。
開発者ツールの要素表示では、現在のDOMを確認できます。ページのソース表示と内容が違う場合でも、JavaScriptによって変更された結果なら不自然ではありません。要素を追加した後、元のHTMLファイルに同じ行が増えていないから失敗したと考えないようにします。保存の仕組みを作っていなければ、再読み込みで初期状態へ戻ることもあります。
※表は横にスクロールできます。
| 見る対象 | 意味 | 確認できること | 混同しやすいこと |
|---|---|---|---|
| HTMLファイル | 初期の文書の記述 | 最初の要素と読み込むスクリプト | DOM変更が自動保存されると思う |
| DOM | 現在の文書構造 | 追加・変更された要素 | ソース表示と常に同じだと思う |
| document | 文書を扱う入口 | 文書からの要素検索 | すべての実行環境にあると思う |
| Element | 取得した一つの要素 | 文字・属性・子要素の操作 | 要素の集まりと同じに扱う |
| NodeList | 複数要素の結果など | 要素を順に処理する | 一つの要素のように更新する |
| イベント | 操作や状態変化の通知 | どの出来事で処理するか | 登録した瞬間に毎回実行されると思う |
実行する時期を決めてから書く
要素を取得する時点で、その要素がまだHTMLの解析によって作られていなければ、見つからない場合があります。初心者の練習では、対象のHTMLを書いた後、bodyの終わり近くにscriptを置くと順番を理解しやすくなります。外部ファイルを読み込む場合は、deferを使うなど、HTMLの解析との関係を考えます。asyncとdeferは同じ意味ではありません。
DOMContentLoadedを待つ方法もありますが、すべての画像などの読み込み完了を待つイベントとして覚えないようにします。文書の解析やスクリプトの読み込み条件と関わるため、MDNのDOMContentLoadedの説明を確認してください。動的に読み込むスクリプトなどでは、既にイベントが終わっている可能性も考える必要があります。まず一つの読み込み方法へ揃えて練習しましょう。
要素を取得して変更する|querySelector・textContent・classList

querySelectorは最初の一致を取得する
querySelectorにはCSSのセレクターを文字列として渡します。idなら#、classなら.を使います。最初に一致する要素を取得し、見つからなければnullになります。MDNのquerySelectorリファレンスも参照し、戻り値が何かを確認してください。セレクターの書き方を間違えると、一致しないだけでなく構文エラーになる場合もあります。
<p id="status">準備中です。</p>
<button id="start-button" type="button">練習を始める</button>
const status = document.querySelector('#status');
const startButton = document.querySelector('#start-button');
console.log(status);
console.log(startButton);
この段階では、まだ画面を変えずに取得結果を確認します。consoleへnullが出ているなら、更新処理を増やす前にHTMLのid、綴り、実行時期を調べます。別の要素が取得されているなら、セレクターが広すぎる可能性があります。ページに複数のボタンがあるとき、buttonだけで探すと意図しない最初の一つへ作用することがあります。
idは文書内で重複しないようにします。部品をコピーした後に同じidが残ると、どちらを取得しているか分かりにくくなります。同じ見た目の複数要素にはclassを使い、それぞれの役割を考えます。CSSの見た目用classとJavaScriptの取得用の目印を分ける設計もありますが、最初は名前の対応が追えることを優先しましょう。
複数の要素は一つずつ扱う
querySelectorAllは一致する要素の一覧を返します。戻り値そのものへtextContentを設定して、全要素の文字が変わると考えないようにします。forEachなどで一つずつ処理する方法を使います。また、querySelectorAllで得られるNodeListは静的なので、後から追加した要素がその結果へ自動的に増えるわけではありません。公式リファレンスでこの性質を確認できます。
const notes = document.querySelectorAll('.note');
notes.forEach((note, index) => {
note.textContent = `補足 ${index + 1}`;
});
後から項目を追加した後の件数を知りたいなら、必要な時点で取り直すか、別の状態管理を考えます。最初に取得した一覧をずっと使い回し、「追加したのに件数が変わらない」と迷った場合は、取得時点を確認してください。何が現在のDOMを反映し、何が取得時の結果なのかを区別すると、更新の不具合を調べやすくなります。
取得する範囲も必要なところへ絞ります。すべてのliを文書全体から探すと、ナビゲーションや別のリストまで含まれる可能性があります。対象のulを先に取得し、その中で探す方が意図を表しやすくなります。短いコードにするために検索範囲を広げるより、どの部品へ作用するかが分かるコードを目指しましょう。
文字を入れるならtextContentから始める
文字だけを表示したい場合はtextContentを使うと、文字列をHTMLとして解析させずに設定できます。利用者が入力した文字をそのままinnerHTMLへ入れるような実装は避けます。MDNのtextContentの説明で、文字として扱う方法とHTMLを扱う方法の違いを確認してください。用途が文字表示なら、必要以上にHTMLを組み立てない方が分かりやすくなります。
const message = document.querySelector('#status');
if (message) {
message.textContent = '練習を始められます。';
}
ただし、親要素のtextContentを丸ごと設定すると、その中にあった子要素も置き換わります。ボタンや入力欄を含む大きな領域へ設定すると、必要な部品が消える原因になります。更新したい文字だけをspanやpへ分け、そこを対象にする方法が役立ちます。安全な文字表示の方法を使っていても、更新範囲が適切かは別に考える必要があります。
入力欄に現在入っている値は、通常valueで読み取ります。inputのtextContentを見ても、期待した入力値を得られるとは限りません。画面へ表示する文章と、フォームの値の扱いを分けて覚えましょう。チェックボックスの選択状態にはcheckedなど、要素の種類に応じたプロパティがあります。見た目が似ている値でも、何を読みたいのかを明確にします。
見た目の変更はclassListで状態を表す
完了した項目に線を引く、選択中のカードを強調するなどの変更は、classListで状態のclassを付け外しし、CSSで見た目を定義する方法が使えます。JavaScriptの中へ色や余白の指定を大量に書くより、状態とデザインを分けて管理しやすくなります。class名には、見た目の色だけでなく状態が分かる言葉を使うと意図が伝わります。
const item = document.querySelector('.task');
if (item) {
item.classList.add('is-done');
item.classList.remove('is-selected');
item.classList.toggle('is-open');
}
※表は横にスクロールできます。
| 操作 | 主な用途 | 使う前の確認 | 注意する点 |
|---|---|---|---|
| querySelector | 一つの対象を取得 | セレクターと実行時期 | nullの可能性がある |
| querySelectorAll | 複数を取得 | 必要な検索範囲 | 静的な一覧である |
| textContent | 文字を表示・更新 | 文字だけの更新対象か | 子要素を置き換える |
| value | 入力欄の現在値 | 対象が入力部品か | 文字列として読む場面が多い |
| classList | 状態のclassを付け外し | 対応するCSSがあるか | 表示と状態を食い違わせない |
イベントを扱う|クリック・入力・フォームの反応を作る

addEventListenerで出来事と処理を結ぶ
イベントリスナーは、指定した出来事が起きたときに処理する関数を登録するものです。ボタンを押したときのclick、入力内容が変わるときのinput、フォーム送信のsubmitなどがあります。何が起きたときに反応してほしいかを先に決め、その出来事に合うイベントを選びます。マウスで押す操作だけを想定せず、キーボードからの操作も考えましょう。
const startButton = document.querySelector('#start-button');
const status = document.querySelector('#status');
if (startButton && status) {
startButton.addEventListener('click', () => {
status.textContent = '最初の項目を確認しましょう。';
});
}
関数を登録する場所で、誤ってその場で実行してしまわないことも大切です。たとえば関数名の後へ括弧を付けるかどうかで意味が変わる場面があります。まず短い無名関数を渡す例で、登録時とクリック時の違いを確かめます。ページを開いた瞬間に処理が走り、ボタンでは何も起きないなら、この部分を確認してください。
MDNのaddEventListenerの説明で、イベントの種類と登録方法を確認できます。後で解除する必要がある場合は、同じ関数の参照を使えるように設計します。最初の練習では、同じリスナーを何度も登録しないことを意識し、一回の操作に対して処理が何回動いたかをconsoleなどで確かめると理解しやすくなります。
入力の途中と確定時を分ける
入力文字数を表示したいなど、入力中に反応させる用途ではinputイベントを検討します。選択の変更を扱う場合にはchangeが合う場面もあります。どのタイミングで発生するかは入力部品によって関係があるため、実際にキーボードや選択操作で試してください。入力するたびに重い処理を動かす必要があるかも考えます。
プログラムからvalueを変えたことが、そのまま利用者の操作と同じイベントを自動で起こすとは限りません。コードで値を更新した後、件数や説明も更新したいなら、その処理を明示的に呼ぶ設計が分かりやすくなります。値の変更、イベント、表示更新を一つのものとして考えず、どこで何を実行しているかを分けましょう。
フォームはsubmitを受け取り、必要な動作だけ止める
チェックリストへ項目を追加するフォームでは、ボタンのclickだけでなくformのsubmitを扱うと、Enterキーによる操作も一つの流れで処理しやすくなります。今回の練習はサーバーへ送信しないため、event.preventDefaultで通常の送信を止め、画面内の一覧へ追加します。何でも止めるのではなく、この練習で不要な標準動作を止める理由を理解してください。
const form = document.querySelector('#task-form');
const input = document.querySelector('#task-input');
if (form && input) {
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
console.log(text);
});
}
この断片では入力値を表示するだけで、項目追加はまだ行いません。空白だけの入力をどう扱うか、追加後に入力欄を空にするか、どこへフォーカスを戻すかを順に決めます。まず値が取得できることを確認し、その後に要素を作る工程を足すと、動かない原因を絞りやすくなります。実際のフォーム送信を作るときは、止めた後に何をするかまで必要です。
event.targetと登録先を区別する
イベントが起きた対象と、リスナーを登録した要素は同じとは限りません。親へリスナーを付け、子のボタンで起きた出来事を受け取る方法もあります。この仕組みを使うと、後から追加される項目の削除ボタンを、一つの親のリスナーで扱える場面があります。どの子で起きたかを確かめ、関係ない場所のクリックへ反応しないようにします。
親へ届くイベントを利用する場合も、すべてのイベントが同じように伝わると考えないようにします。イベントの種類、キャプチャ、バブリングなどを必要に応じて学びます。初心者の練習では、clickやchangeを使う単純な範囲から始め、stopPropagationを原因不明のまま追加しないことが大切です。伝わり方を止めると、別の処理へ影響する場合があります。
※表は横にスクロールできます。
| イベント | 練習で使う場面 | 対象の考え方 | 確認する操作 |
|---|---|---|---|
| click | ボタンの反応 | 押された要素と登録先を分ける | マウスとキーボード |
| input | 入力中の説明更新 | 現在のvalueを読む | 入力・貼り付け・削除 |
| change | チェック状態の変更 | checkedなどを読む | オンとオフの両方 |
| submit | フォームの追加処理 | formへ登録する | ボタンとEnterキー |
| DOMContentLoaded | 文書解析後の初期化 | 実行時期を合わせる | 読み込み方法との関係 |
要素を追加・削除する|小さなチェックリストを組む

作成と挿入を分けて考える
createElementで要素を作っただけでは、通常そのまま画面へ現れません。文字や属性を設定し、表示したい親へappendなどで挿入します。作る、整える、入れるという順に分けると、どこまでできているか確認しやすくなります。作成した要素をconsoleで見た後、親へ追加して画面へ現れることを試しましょう。
const list = document.querySelector('#task-list');
const item = document.createElement('li');
item.textContent = '見出し構造を確認する';
if (list) {
list.append(item);
}
既に文書にある同じ要素を別の場所へappendすると、複製ではなく移動になる場面があります。同じ見た目の項目を増やしたいなら、新しい要素を作るか、複製の方法を考えます。要素の参照を一つだけ使い回して何度も追加し、「最後の一つしかない」と迷った場合は、この違いを確認してください。
削除は、対象の要素へremoveを使う方法があります。削除ボタン自体を消したいのか、それを含む項目全体を消したいのかを区別します。最も近いliを探すなど、構造に合う対象を選んでください。対象を広く取りすぎると、一覧全体を消してしまう可能性があります。小さな仮の一覧で、どこが消えるか確かめることが大切です。
動く部品を一つのページへまとめる
次の完全例は、項目の追加、完了状態、削除、件数更新を行います。ブラウザーで開く練習用HTMLとして保存してください。内容はメモリー上のDOMだけにあり、再読み込みすると消えます。永続的なメモ帳や業務の記録として使わず、仮の学習項目で試しましょう。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DOMチェックリストの練習</title>
<style>
* { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, sans-serif; line-height: 1.7; color: #21303f; }
main { max-width: 44rem; padding: 1.5rem; margin: auto; }
form { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: end; }
.field { flex: 1 1 16rem; }
.field label { display: block; font-weight: 700; }
input[type="text"] { width: 100%; padding: 0.7rem; font: inherit; }
button { padding: 0.7rem 1rem; font: inherit; cursor: pointer; }
ul { padding: 0; list-style: none; }
li { display: flex; gap: 1rem; align-items: center; padding: 1rem 0; border-bottom: 1px solid #b3bec8; }
li label { flex: 1; min-width: 0; overflow-wrap: anywhere; }
li input { margin-right: 0.5rem; }
.is-done .task-text { text-decoration: line-through; color: #52616c; }
:focus-visible { outline: 3px solid #8e3eb3; outline-offset: 3px; }
#message { min-height: 2em; }
</style>
</head>
<body>
<main>
<h1>学習チェックリスト</h1>
<p>練習用です。再読み込みすると項目は消えます。</p>
<form id="task-form">
<div class="field">
<label for="task-input">追加する項目(80文字以内)</label>
<input id="task-input" name="task" type="text" maxlength="80" required>
</div>
<button type="submit">追加する</button>
</form>
<p id="summary">0件中0件が完了</p>
<p id="message" role="status"></p>
<ul id="task-list" aria-label="学習項目"></ul>
</main>
<script>
const form = document.querySelector('#task-form');
const input = document.querySelector('#task-input');
const list = document.querySelector('#task-list');
const summary = document.querySelector('#summary');
const message = document.querySelector('#message');
function updateSummary() {
const total = list.children.length;
const done = list.querySelectorAll('input[type="checkbox"]:checked').length;
summary.textContent = `${total}件中${done}件が完了`;
}
function addTask(text) {
const item = document.createElement('li');
const label = document.createElement('label');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
const span = document.createElement('span');
span.className = 'task-text';
span.textContent = text;
const removeButton = document.createElement('button');
removeButton.type = 'button';
removeButton.dataset.action = 'remove';
removeButton.textContent = '削除';
removeButton.setAttribute('aria-label', `${text}を削除`);
label.append(checkbox, span);
item.append(label, removeButton);
list.append(item);
}
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text || text.length > 80) {
message.textContent = '空白以外の文字を80文字以内で入力してください。';
input.focus();
return;
}
addTask(text);
input.value = '';
updateSummary();
message.textContent = '項目を追加しました。';
input.focus();
});
list.addEventListener('change', (event) => {
const target = event.target;
if (!(target instanceof HTMLInputElement) || target.type !== 'checkbox') return;
const item = target.closest('li');
if (!item || !list.contains(item)) return;
item.classList.toggle('is-done', target.checked);
updateSummary();
message.textContent = target.checked ? '完了にしました。' : '未完了に戻しました。';
});
list.addEventListener('click', (event) => {
const target = event.target;
if (!(target instanceof Element)) return;
const button = target.closest('button[data-action="remove"]');
if (!button || !list.contains(button)) return;
const item = button.closest('li');
if (!item) return;
item.remove();
updateSummary();
message.textContent = '項目を削除しました。';
input.focus();
});
</script>
</body>
</html>
この例では、入力した文字をspanのtextContentへ入れています。HTMLの断片を文字列としてつないで一覧全体へ入れ直す方法を使っていません。項目を追加するときに要素を作り、変更された項目だけclassを変え、削除するときに対象のliだけを消します。更新範囲が小さいため、他の入力部品を誤って置き換えにくくなります。
完了状態と件数を同じタイミングで更新する
チェックボックスの状態を変えたら、見た目のclassと件数を更新します。classだけ変えて件数を変えないと、画面内で情報が食い違います。追加と削除でも件数が変わるため、共通のupdateSummary関数へまとめています。同じ計算を複数の場所へ別々に書くより、修正時に漏れを減らせます。
この小さな例では現在のDOMから件数を計算しています。項目が多いアプリや複雑な状態を扱う場合は、配列などのデータを正本として表示へ反映する設計も考えます。どちらでも、どの情報が現在の状態を表すのかを明確にすることが重要です。DOMと配列を別々に更新して内容がずれるような運用を避け、状態と表示の関係を整理しましょう。
追加した後の操作とフォーカスを確認する
新しく追加した項目にも、完了と削除の操作が働くかを確認します。今回の例は一覧の親へリスナーを付けているため、追加後の子で起きた対象イベントも扱います。もし最初の項目だけにリスナーを登録していたら、後から増えた項目へ同じ処理が付くとは限りません。動的に増える要素では、いつ誰へ登録するかを考える必要があります。
削除した後、フォーカスが失われて操作を続けにくくならないかも見ます。例では入力欄へ戻していますが、実際のアプリでは次の項目のボタンへ移す方が自然な場合もあります。追加、完了、削除の順にマウスを使わず試し、どこへ移動するかを観察してください。画面の表示が変わることだけでなく、次の操作へ進めることまで確認します。
※表は横にスクロールできます。
| 操作 | 変わるDOM | 一緒に更新するもの | 練習で試す条件 |
|---|---|---|---|
| 追加 | 新しいliと子要素 | 件数・入力欄・通知 | 空白・短文・80文字付近 |
| 完了 | 対象liのclass | 完了件数・通知 | オンとオフを繰り返す |
| 削除 | 対象liを取り除く | 件数・通知・フォーカス | 先頭・中央・最後の項目 |
| 再読み込み | 初期HTMLへ戻る | 保存しない仕様の説明 | 項目が残らないことを理解する |
| 文字表示 | spanのtextContent | 必要に応じた読みやすさ | 記号や長い文字列を入れる |
動かない原因を調べる|null・実行時期・安全性と検証

最初のエラーから順番に読む
動かないときは、開発者ツールのconsoleを確認します。最初のエラーによって、その後の処理が実行されていない場合があります。表示が変わらない場所だけを見てCSSを直す前に、JavaScriptの構文、変数名、取得結果を確認してください。エラー文の行番号と、実際に読み込まれたファイルの内容を対応させます。
nullに対してプロパティを読もうとしている場合は、対象が取得できていない可能性があります。idの綴り、セレクターの記号、HTMLにその要素があるか、実行時期の順に見ます。nullなら何もしない条件を付けるだけで、必要な部品が見つからない原因を放置しないようにしましょう。任意の部品でないなら、なぜ存在しないのかを修正する必要があります。
変数が定義されていない場合は、名前の違いと有効な範囲を確認します。関数の中で作った変数を外から使おうとしているなど、DOMとは別のJavaScriptの基礎が原因のこともあります。取得、イベント、更新のどこまで動いたかを短いconsole.logで確かめ、問題を小さく切り分けます。機密情報をconsoleへ出さない配慮も忘れないでください。
二重に動くときは登録回数を見る
一回押したのに二つ追加される場合、リスナーを重複登録していないか確認します。初期化関数を何度も呼んでいる、同じスクリプトを二回読み込んでいる、ボタンのclickとformのsubmitの両方で同じ追加処理をしているなどの可能性があります。症状を抑えるために無関係なフラグを増やす前に、どこで登録されているかを探しましょう。
逆に、一覧をinnerHTMLなどで作り直した後にボタンが反応しなくなる場合は、以前の要素へ付けていたリスナーと、新しくできた要素の関係を確認します。同じ見た目でも、別の要素として作られていることがあります。必要な部品を部分的に更新するか、適切な親でイベントを扱うかなど、構造に合った方法を選びます。
外部の文字列をHTMLとして扱わない
利用者が入力した文字、URLから受け取った値、外部サービスのデータを表示するときは、信頼できるHTMLと同じように扱わないことが重要です。文字を見せる用途ならtextContentを使い、HTMLとして解釈する必要がある場合は、別途安全な処理を検討します。単に危険そうな一文字を消すだけで、あらゆる問題を防げると考えないようにしましょう。
リンク先や画像のURLなどを動的に設定する場合も、文字として表示する処理とは条件が違います。許可する宛先や方式を確認する必要がある場面があります。また、画面でボタンを隠したことを、サーバー側の権限確認の代わりにしないでください。DOMは利用者側で変更できるため、重要な処理の許可は信頼できる側で判断する必要があります。
今回のチェックリストは外部通信をせず、入力値を文字として表示する小さな練習です。これを業務システムへ発展させる場合は、保存、共有、権限、入力の検証などを追加で考えます。DOM操作ができることと、複数人が安全に使うアプリを完成させることの間にある範囲を理解し、段階的に学びましょう。
※表は横にスクロールできます。
| 症状 | 主な確認先 | 切り分ける試し方 | 避けたい直し方 |
|---|---|---|---|
| 何も変わらない | 取得結果・console | 取得直後の値を見る | 理由なく待ち時間を増やす |
| nullエラー | id・セレクター・実行時期 | HTML解析後に対象を確認 | 必要な要素の欠落を無視する |
| 二重に追加される | 登録回数とイベント | 一回の操作のログ回数を見る | 重複原因を残して見た目だけ消す |
| 追加後の項目だけ動かない | 登録した対象と時期 | 新しい要素の構造を見る | 古い一覧を永続的な結果と思う |
| ボタンが消えた | 親への文字・HTML更新 | 更新範囲を狭めて試す | 大きな領域を毎回作り直す |
| 再読み込みで消える | 保存機能の有無 | 初期化の流れを確認 | DOM変更がファイルへ保存されると思う |
動作確認を小さな組み合わせで行う
完成例では、まず一つ追加し、完了へ変え、未完了へ戻し、削除します。その後、複数項目を追加して中央の一つを削除し、残りのチェック状態と件数が正しいかを見ます。空白だけ、長い文字、記号を含む文字も試してください。成功する一通りだけでなく、順番を変えたときにも整合しているかを確認することが大切です。
修正をしたら、関係する操作をもう一度試します。削除処理を変えた場合は、件数だけでなくフォーカスと完了状態も見ます。リスナーの登録方法を変えた場合は、追加前後の項目の両方を確認します。テストの結果は、ブラウザー、操作の順番、入力例、期待した結果、実際の結果で残すと、後から不具合を再現しやすくなります。
DOMの練習からWeb制作を広げ、質問しながら学びたい場合は、副業向けプログラミングスクールの料金・教材・支援比較も参考になります。JavaScriptの文法で困っているのか、HTML構造とイベントの関係で困っているのかを整理すると、必要な支援を比べやすくなります。ライブラリやフレームワークへ進む場合も、要素、状態、イベントの関係を理解していることが役立ちます。
DOM操作は、対象を取得し、出来事を受け取り、必要な部分だけ更新するという流れから始められます。最初のチェックリストで、どの要素が作られ、どのリスナーが動き、どの表示が変わるかを一つずつ追ってください。動いた結果を眺めるだけでなく、その理由を説明できることが、次の機能を自分で作るための基礎になります。