JavaScript

JavaScriptのDOMとイベント:入力・追加・削除ができるメモ一覧を作る

この記事でわかること

JavaScriptで入力・追加・削除ができるメモ一覧を実装。DOM取得、createElement、submitイベント、textContent、フォーカスの扱いを学びます。

第4回では、ブラウザーの入力欄とボタンをJavaScriptから扱います。HTML要素を取得し、イベントに応じて新しい要素を作る流れを確認します。Reactなどのフレームワークを使わない小さなメモ一覧です。

HTMLの構造を作る

index.htmlを保存する

新しい作業用フォルダーへindex.htmlを保存します。入力欄はラベルと関連付け、結果の件数を通知する領域を用意します。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>JavaScriptのメモ一覧</title>
</head>
<body>
  <main>
    <h1>メモ一覧</h1>
    <form id="memo-form">
      <label for="memo-input">メモ</label>
      <input id="memo-input" name="memo" required maxlength="100">
      <button type="submit">追加</button>
    </form>
    <p id="status" role="status">0件のメモ</p>
    <ul id="memo-list"></ul>
  </main>
  <script type="module" src="./app.js"></script>
</body>
</html>

moduleとしてスクリプトを読み込む

type="module"を指定して読み込みます。モジュールスクリプトは通常、HTMLの解析後に実行されるため、先に書いた要素を取得できます。Node.jsの例と違い、このコードはブラウザー上で実行します。

イベントでDOMを更新する

app.jsを作成する

同じフォルダーにapp.jsを保存します。ユーザーが入力したメモはtextContentで表示し、HTMLとして解釈しません。

const form = document.getElementById('memo-form');
const input = document.getElementById('memo-input');
const list = document.getElementById('memo-list');
const status = document.getElementById('status');

if (!form || !input || !list || !status) {
  throw new Error('必要なHTML要素がありません。');
}

function updateStatus() {
  status.textContent = `${list.children.length}件のメモ`;
}

form.addEventListener('submit', (event) => {
  event.preventDefault();
  const text = input.value.trim();
  if (!text) {
    status.textContent = '空白だけのメモは追加できません。';
    input.focus();
    return;
  }

  const row = document.createElement('li');
  const label = document.createElement('span');
  const removeButton = document.createElement('button');
  label.textContent = text;
  removeButton.type = 'button';
  removeButton.textContent = '削除';
  removeButton.setAttribute('aria-label', `${text}を削除`);
  removeButton.addEventListener('click', () => {
    row.remove();
    updateStatus();
    input.focus();
  });

  row.append(label, ' ', removeButton);
  list.append(row);
  input.value = '';
  updateStatus();
  input.focus();
});

preventDefaultで送信時の移動を止める

フォーム送信時の標準動作を止め、このページ内でメモを追加します。クリックイベントだけでなくsubmitを使うため、入力欄からEnterキーでも操作できます。

textContentとinnerHTMLを区別する

textContentは文字として表示します。たとえば<strong>大事</strong>と入力しても、太字のHTMLにはなりません。ユーザー入力をそのままinnerHTMLへ入れると、意図しないHTMLとして扱う危険があるため、この用途では使いません。

ローカルサーバーで開く

HTTP経由で表示する

Python 3が使える環境なら、作業フォルダーで次を実行します。file://で開く方法はモジュールの読み込み制約があるため、HTTPで確認します。

python3 -m http.server 8080 --bind 127.0.0.1

ブラウザーでhttp://localhost:8080/を開きます。サーバーを止めるときはターミナルでCtrl+Cを押します。

操作を確認する

  • メモを追加すると、一覧と件数が増えます。
  • 空欄はブラウザーの必須入力チェック、空白だけはJavaScript側で拒否します。
  • 削除すると件数が減り、入力欄へフォーカスが戻ります。
  • HTMLに見える文字列を入力しても、文字として表示されます。
  • 再読み込みするとメモは消えます。この例は保存機能を持ちません。

実装を広げるときの注意

DOMとデータの役割を整理する

この小さな例ではDOMを一覧の状態として使っています。並び替えや永続化が必要になったら、配列をデータの本体として保持し、そのデータからDOMを更新する構成を検討します。

イベント登録の寿命を考える

今回はページの寿命と同じ期間だけフォームを使います。画面を何度も初期化する構成では、同じ要素への二重登録を避け、不要になったイベントを解除する設計が必要です。

参考資料と次の学習

非同期処理へ進む

次はPromise・async/await・fetchで、時間のかかる処理と失敗を扱います。

参考資料

y.
WRITTEN BY

y_ymo10

SEの部屋で、JavaScript・TypeScript・React.js・Next.jsの開発ノートを公開しています。

ほかの開発ノートを読む →