基礎から学ぶJavaScript入門 90日コース | Webページを操作するDOM - Day 41:DOM操作演習

JavaScript 90日で身につけるJavaScript
スポンサーリンク
スポンサーリンク
  1. Day 41:DOM操作演習(前半)
  2. 文字数カウンターの全体像をイメージする
    1. 文字数カウンターがあると何が嬉しいか
  3. 基本のHTML構造を作る
    1. 入力欄と文字数表示エリアを用意する
  4. JavaScriptでDOM要素を取得する
    1. 文字数カウンターに必要な要素を変数にまとめる
  5. 入力イベントで文字数をカウントする
    1. inputイベントとは何か
    2. 現在の文字数を取得する
  6. 文字数表示を更新する
    1. 文字数を画面に表示する
  7. 最大文字数警告を表示する
    1. 最大文字数を超えたかどうかを判定する
    2. 警告メッセージとスタイルを切り替える
  8. 完成コード(コメント付き)
  9. 少しだけ発展させる:残り文字数を表示する
    1. 残り文字数を計算する
  10. セキュリティ・安全性の観点からの補足
  11. Day 41 前半 練習用テンプレート
  12. Day 41 前半のまとめ
  13. Day 41:DOM操作演習(後半)
  14. 文字数カウンターを“ユーザー目線”で考え直す
    1. 何を表示すると、ユーザーは安心して入力できるか
  15. 基本構造を少し拡張する
    1. 送信ボタンと残り文字数表示を追加する
  16. JavaScriptで“状態”をまとめて管理する
    1. 必要なDOM要素と最大文字数を定義する
    2. 状態更新の“中心となる関数”を作る
  17. inputイベントで状態更新関数を呼び出す
    1. 入力が変わるたびに updateCounterState() を呼ぶ
    2. 初期状態でも一度呼んでおく
  18. 送信ボタンのクリック処理を追加する
    1. 送信ボタンが押されたときの挙動
  19. 完成コード(発展版文字数カウンター)
  20. 複数の入力欄に文字数カウンターを適用する
    1. 同じ仕組みを“再利用できる形”にする
  21. セキュリティ・ユーザー体験の視点からのまとめ
    1. セキュリティの基本を守る
    2. ユーザー体験を意識した設計
  22. Day 41 後半 練習用テンプレート
  23. Day 41 後半のまとめ

Day 41:DOM操作演習(前半)

「文字数カウンターを通して“DOM操作の流れ”を体で覚える」

Day 41前半では、これまで学んできた DOM操作・イベント処理・フォーム操作 をまとめて使う演習として、 シンプルだけれど実務でもよく使われる 「文字数カウンター」 を作成していきます。

今回のゴールは、次の3つの機能を持つミニアプリです。

  • テキスト入力
  • 文字数表示
  • 最大文字数警告

この演習を通して、

「ユーザーの入力 → イベント発生 → DOMを書き換え → 状態を表示」

という一連の流れを、自然に書けるようになることを目指します。

文字数カウンターの全体像をイメージする

文字数カウンターがあると何が嬉しいか

文字数カウンターは、次のような場面でよく使われます。

  • SNSの投稿フォーム(例:最大140文字まで)
  • お問い合わせフォームの「ご意見」欄(例:最大500文字まで)
  • ブログのタイトル入力(例:最大50文字まで)

ユーザーにとっては、

  • 「あと何文字書けるか」が分かる
  • 「書きすぎたかどうか」がすぐに分かる

というメリットがあります。

開発者にとっては、

  • 入力制限を視覚的に伝えられる
  • バリデーション(入力チェック)の一部をUIで補助できる

という利点があります。

基本のHTML構造を作る

まずは、文字数カウンターの土台となるHTMLを用意します。

入力欄と文字数表示エリアを用意する

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 41 前半:文字数カウンター</title>
  <style>
    /* 最大文字数を超えたときの警告表示用のスタイル */
    .warning {
      color: red;
      font-weight: bold;
    }
  </style>
</head>
<body>
  <h1>文字数カウンター演習</h1>

  <!-- ▼ テキスト入力欄 -->
  <label for="textInput">テキストを入力してください:</label><br>
  <textarea id="textInput" rows="4" cols="40" placeholder="ここにテキストを入力します"></textarea>

  <!-- ▼ 文字数表示エリア -->
  <p id="counter">現在の文字数:0文字</p>

  <!-- ▼ 最大文字数警告エリア -->
  <p id="warningMessage"></p>

  <script>
    // ここにJavaScriptを書いていきます
  </script>
</body>
</html>

ここでのポイントは、

  • 入力欄として <textarea> を使っていること
  • 現在の文字数を表示する <p id="counter"> を用意していること
  • 警告メッセージ用に <p id="warningMessage"> を用意していること

です。

JavaScriptでDOM要素を取得する

文字数カウンターに必要な要素を変数にまとめる

// ▼ テキスト入力欄の要素を取得します
const textInputElement = document.getElementById('textInput');

// ▼ 文字数表示用の要素を取得します
const counterElement = document.getElementById('counter');

// ▼ 警告メッセージ表示用の要素を取得します
const warningMessageElement = document.getElementById('warningMessage');

// ▼ 最大文字数を定義します(ここでは100文字とします)
const MAX_LENGTH = 100;
JavaScript

ここでのポイントは、

  • DOM要素を変数に入れておくことで、後の処理が読みやすくなること
  • MAX_LENGTH を定数として定義しておくことで、 「どこが最大文字数の設定か」が一目で分かること

です。

入力イベントで文字数をカウントする

inputイベントとは何か

textareainput に対しては、 ユーザーが文字を入力・削除するたびに input イベント が発生します。

textInputElement.addEventListener('input', function () {
  // 入力内容が変わるたびに呼ばれる処理
});
JavaScript

input イベントは、

「フォームの内容が変わった瞬間に反応したい」

ときに使うイベントで、 文字数カウンターにはぴったりです。

現在の文字数を取得する

textarea の現在の内容は、 value プロパティから取得できます。

textInputElement.addEventListener('input', function () {
  // ▼ 現在の入力内容を取得します
  const currentText = textInputElement.value;

  // ▼ 文字数を数えます
  const currentLength = currentText.length;

  console.log('現在の文字数:', currentLength);
});
JavaScript

ここでのポイントは、

  • value は「フォームの中身」を表すプロパティであること
  • .length で文字数を取得できること

です。

文字数表示を更新する

文字数を画面に表示する

取得した文字数を、 counterElement のテキストとして表示します。

textInputElement.addEventListener('input', function () {
  const currentText = textInputElement.value;
  const currentLength = currentText.length;

  // ▼ 文字数表示を更新します
  counterElement.textContent = `現在の文字数:${currentLength}文字`;
});
JavaScript

ここで textContent を使っているのは、 ユーザー入力を安全にテキストとして扱うためです。

innerHTML を使うと、 入力された文字列がHTMLとして解釈されてしまい、 <script> などが実行される危険があるため、 文字数カウンターのような場面では textContent が適切です。

最大文字数警告を表示する

最大文字数を超えたかどうかを判定する

次に、現在の文字数が MAX_LENGTH を超えたかどうかを判定します。

textInputElement.addEventListener('input', function () {
  const currentText = textInputElement.value;
  const currentLength = currentText.length;

  counterElement.textContent = `現在の文字数:${currentLength}文字`;

  // ▼ 最大文字数を超えたかどうかを判定します
  if (currentLength > MAX_LENGTH) {
    // 超えた場合の処理
  } else {
    // 超えていない場合の処理
  }
});
JavaScript

警告メッセージとスタイルを切り替える

最大文字数を超えた場合は、 警告メッセージを表示し、 見た目も分かりやすく変えます。

if (currentLength > MAX_LENGTH) {
  // ▼ 警告メッセージを表示します
  warningMessageElement.textContent = `最大文字数(${MAX_LENGTH}文字)を超えています。`;

  // ▼ 警告用のスタイルを適用します
  warningMessageElement.classList.add('warning');
} else {
  // ▼ 警告メッセージを消します
  warningMessageElement.textContent = '';

  // ▼ 警告用のスタイルを外します
  warningMessageElement.classList.remove('warning');
}
JavaScript

ここでのポイントは、

  • classList.add()classList.remove() を使って、 状態に応じてCSSクラスを付け外ししていること
  • 「ロジック(JavaScript)」と「見た目(CSS)」を分けていること

です。

完成コード(コメント付き)

ここまでの内容を1つにまとめた完成コードです。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 41 前半:文字数カウンター</title>
  <style>
    /* ▼ 最大文字数を超えたときの警告表示用のスタイル */
    .warning {
      color: red;
      font-weight: bold;
    }
  </style>
</head>
<body>
  <h1>文字数カウンター演習</h1>

  <!-- ▼ テキスト入力欄 -->
  <label for="textInput">テキストを入力してください:</label><br>
  <textarea
    id="textInput"
    rows="4"
    cols="40"
    placeholder="ここにテキストを入力します"
  ></textarea>

  <!-- ▼ 文字数表示エリア -->
  <p id="counter">現在の文字数:0文字</p>

  <!-- ▼ 最大文字数警告エリア -->
  <p id="warningMessage"></p>

  <script>
    // ▼ DOM要素を取得します
    const textInputElement = document.getElementById('textInput');
    const counterElement = document.getElementById('counter');
    const warningMessageElement = document.getElementById('warningMessage');

    // ▼ 最大文字数を定義します
    const MAX_LENGTH = 100;

    // ▼ 入力内容が変わるたびに文字数をカウントする処理
    textInputElement.addEventListener('input', function () {
      // 現在の入力内容を取得します
      const currentText = textInputElement.value;

      // 文字数を数えます
      const currentLength = currentText.length;

      // 文字数表示を更新します
      counterElement.textContent = `現在の文字数:${currentLength}文字`;

      // 最大文字数を超えたかどうかを判定します
      if (currentLength > MAX_LENGTH) {
        // 超えた場合は警告メッセージを表示し、スタイルを変更します
        warningMessageElement.textContent = `最大文字数(${MAX_LENGTH}文字)を超えています。`;
        warningMessageElement.classList.add('warning');
      } else {
        // 超えていない場合は警告を消します
        warningMessageElement.textContent = '';
        warningMessageElement.classList.remove('warning');
      }
    });
  </script>
</body>
</html>

少しだけ発展させる:残り文字数を表示する

文字数カウンターは、 「現在の文字数」だけでなく 「残り文字数」 を表示すると、さらに使いやすくなります。

残り文字数を計算する

const remainingLength = MAX_LENGTH - currentLength;
JavaScript

これを使って、 次のような表示にすることもできます。

if (remainingLength >= 0) {
  counterElement.textContent = `現在の文字数:${currentLength}文字(残り:${remainingLength}文字)`;
} else {
  counterElement.textContent = `現在の文字数:${currentLength}文字(${-remainingLength}文字オーバー)`;
}
JavaScript

このように、 「ユーザーにとって知りたい情報は何か」 を考えながら表示内容を設計することも、 DOM操作演習の大事な一部です。

セキュリティ・安全性の観点からの補足

文字数カウンターは一見シンプルですが、 次のような点を意識しておくと、 より安全で堅牢なコードになります。

  • ユーザー入力を画面に表示するときは、必ず textContent を使う
    • innerHTML を使うと、入力された文字列がHTMLとして解釈されてしまい、 <script> などが実行される危険があります。
  • 最大文字数を超えたときに、 ただ警告するだけでなく「送信ボタンを無効化する」などの対策も考えられます。
  • 入力値の扱いは、 フロントエンドだけでなくバックエンド側でも必ずチェックする必要があります。

今回の演習ではフロント側のUIに集中していますが、 こうした安全性の視点を持っておくことは、 どんな規模のアプリでも役に立ちます。

Day 41 前半 練習用テンプレート

最後に、今日の内容をそのまま試せる練習用テンプレートを紹介します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 41 前半:文字数カウンター 練習テンプレート</title>
  <style>
    .warning {
      color: red;
      font-weight: bold;
    }
  </style>
</head>
<body>
  <h1>文字数カウンター 練習</h1>

  <textarea id="textInput" rows="4" cols="40" placeholder="テキストを入力"></textarea>
  <p id="counter">現在の文字数:0文字</p>
  <p id="warningMessage"></p>

  <script>
    console.log('--- 文字数カウンター 練習開始 ---');

    const textInputElement = document.getElementById('textInput');
    const counterElement = document.getElementById('counter');
    const warningMessageElement = document.getElementById('warningMessage');
    const MAX_LENGTH = 100;

    textInputElement.addEventListener('input', () => {
      const text = textInputElement.value;
      const length = text.length;

      counterElement.textContent = `現在の文字数:${length}文字`;

      if (length > MAX_LENGTH) {
        warningMessageElement.textContent = `最大文字数(${MAX_LENGTH}文字)を超えています。`;
        warningMessageElement.classList.add('warning');
      } else {
        warningMessageElement.textContent = '';
        warningMessageElement.classList.remove('warning');
      }

      console.log('文字数:', length);
    });

    console.log('--- 文字数カウンター 練習テンプレートの準備が完了しました ---');
  </script>
</body>
</html>

Day 41 前半のまとめ

Day 41前半では、

  • テキスト入力欄・文字数表示・警告表示という3つの要素を組み合わせて、 シンプルな文字数カウンターを作成したこと。
  • input イベントでユーザーの入力変化を検知し、 value.length で文字数を取得する流れを体験したこと。
  • textContent を使って安全に文字数や警告メッセージを表示し、 classList.add()remove() で状態に応じて見た目を切り替えたこと。
  • 「ユーザーにとって知りたい情報は何か」を考えながら、 残り文字数などの発展もイメージしたこと。

を整理しました。

この演習は、 フォームバリデーションやリアルタイムフィードバックなど、 多くのWebアプリでそのまま応用できるパターンです。


Day 41:DOM操作演習(後半)

「文字数カウンターを“実用レベル”に育てて、DOM操作の設計力を鍛える」

Day 41後半では、前半で作成した文字数カウンターをさらに発展させて、 「実際のサービスでもそのまま使えるレベル」 を目指していきます。

テーマは同じく、

  • テキスト入力
  • 文字数表示
  • 最大文字数警告

ですが、後半では次のようなポイントを意識して深掘りしていきます。

  • 残り文字数の表示
  • 最大文字数を超えたときの送信ボタン制御
  • 複数の入力欄に対する文字数カウンター
  • セキュリティ・ユーザー体験を意識した設計

「ただ動く」から一歩進んで、 「ユーザーにとって気持ちよく使える文字数カウンター」 を設計していきます。

文字数カウンターを“ユーザー目線”で考え直す

何を表示すると、ユーザーは安心して入力できるか

前半では「現在の文字数」と「最大文字数警告」を作りましたが、 ユーザー目線で考えると、次のような情報もあると便利です。

  • 残り文字数(あと何文字書けるか)
  • オーバーした文字数(何文字書きすぎているか)
  • 送信ボタンが押せるかどうか(制限を超えたら押せない)

これらを追加することで、

「入力しながら、常に自分の状態が分かるフォーム」

に近づいていきます。

基本構造を少し拡張する

送信ボタンと残り文字数表示を追加する

まずは、前半のHTMLに少しだけ要素を追加します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 41 後半:文字数カウンター発展</title>
  <style>
    .warning {
      color: red;
      font-weight: bold;
    }
    .disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }
  </style>
</head>
<body>
  <h1>文字数カウンター発展編</h1>

  <!-- ▼ テキスト入力欄 -->
  <label for="textInput">テキストを入力してください:</label><br>
  <textarea
    id="textInput"
    rows="4"
    cols="40"
    placeholder="ここにテキストを入力します"
  ></textarea>

  <!-- ▼ 現在の文字数表示 -->
  <p id="counter">現在の文字数:0文字</p>

  <!-- ▼ 残り文字数表示 -->
  <p id="remaining">残り文字数:100文字</p>

  <!-- ▼ 最大文字数警告エリア -->
  <p id="warningMessage"></p>

  <!-- ▼ 送信ボタン -->
  <button id="submitButton">送信</button>

  <script>
    // ここにJavaScriptを書いていきます
  </script>
</body>
</html>

追加したのは、

  • 残り文字数表示用の <p id="remaining">
  • 送信ボタン <button id="submitButton">
  • ボタンの見た目を変えるための .disabled クラス

です。

JavaScriptで“状態”をまとめて管理する

必要なDOM要素と最大文字数を定義する

const textInputElement = document.getElementById('textInput');
const counterElement = document.getElementById('counter');
const remainingElement = document.getElementById('remaining');
const warningMessageElement = document.getElementById('warningMessage');
const submitButtonElement = document.getElementById('submitButton');

// ▼ 最大文字数を定義します
const MAX_LENGTH = 100;
JavaScript

ここまでは前半と似ていますが、 後半では 「状態をまとめて更新する関数」 を作ることが重要になります。

状態更新の“中心となる関数”を作る

文字数カウンターの状態は、

  • 現在の文字数
  • 残り文字数
  • 警告メッセージ
  • 送信ボタンの有効/無効

など、複数の要素にまたがっています。

これらをバラバラに更新すると、 コードが散らばって分かりにくくなるので、 「状態更新の中心となる関数」 を作ります。

function updateCounterState() {
  // ▼ 現在の入力内容と文字数を取得します
  const currentText = textInputElement.value;
  const currentLength = currentText.length;

  // ▼ 残り文字数を計算します
  const remainingLength = MAX_LENGTH - currentLength;

  // ▼ 現在の文字数表示を更新します
  counterElement.textContent = `現在の文字数:${currentLength}文字`;

  // ▼ 残り文字数表示を更新します
  if (remainingLength >= 0) {
    remainingElement.textContent = `残り文字数:${remainingLength}文字`;
  } else {
    remainingElement.textContent = `残り文字数:0文字(${-remainingLength}文字オーバー)`;
  }

  // ▼ 最大文字数警告とボタン制御を更新します
  if (currentLength > MAX_LENGTH) {
    warningMessageElement.textContent = `最大文字数(${MAX_LENGTH}文字)を超えています。`;
    warningMessageElement.classList.add('warning');

    // 送信ボタンを無効化します
    submitButtonElement.disabled = true;
    submitButtonElement.classList.add('disabled');
  } else {
    warningMessageElement.textContent = '';
    warningMessageElement.classList.remove('warning');

    // 送信ボタンを有効化します
    submitButtonElement.disabled = false;
    submitButtonElement.classList.remove('disabled');
  }
}
JavaScript

ここでの重要ポイントは、

  • 文字数・残り文字数・警告・ボタン制御を 1つの関数でまとめて更新している こと
  • remainingLength がマイナスになった場合に「オーバーした文字数」を表示していること
  • ボタンの disabled プロパティと .disabled クラスを組み合わせて、 見た目と機能の両方を制御していること

です。

inputイベントで状態更新関数を呼び出す

入力が変わるたびに updateCounterState() を呼ぶ

textInputElement.addEventListener('input', function () {
  updateCounterState();
});
JavaScript

これで、

  • ユーザーが入力するたびに
  • 現在の文字数・残り文字数・警告・ボタン状態が
  • 一括で更新される

という流れができました。

初期状態でも一度呼んでおく

ページを開いた直後にも、 初期状態を反映しておくと親切です。

// ▼ ページ読み込み直後に初期状態を反映します
updateCounterState();
JavaScript

これにより、

  • 入力が空の状態でも「残り文字数:100文字」と表示される
  • ボタンが最初から正しい状態になっている

という、気持ちよい初期状態になります。

送信ボタンのクリック処理を追加する

送信ボタンが押されたときの挙動

文字数カウンターの演習として、 送信ボタンが押されたときに簡単なメッセージを表示してみます。

submitButtonElement.addEventListener('click', function () {
  const currentText = textInputElement.value;
  const currentLength = currentText.length;

  // ▼ 最大文字数を超えている場合は送信させません(念のためチェック)
  if (currentLength > MAX_LENGTH) {
    alert(`最大文字数(${MAX_LENGTH}文字)を超えているため、送信できません。`);
    return;
  }

  // ▼ 実際のアプリではここでサーバーに送信します
  alert('送信しました:\n' + currentText);
});
JavaScript

ここでのポイントは、

  • ボタンの disabled で制御していても、 念のためクリック時にも最大文字数チェックをしていること
  • フロント側のUIだけでなく、 ロジック側でも必ず制限を確認する習慣 を持つこと

です。

完成コード(発展版文字数カウンター)

ここまでの内容を1つにまとめた完成コードです。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 41 後半:文字数カウンター発展</title>
  <style>
    .warning {
      color: red;
      font-weight: bold;
    }
    .disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }
  </style>
</head>
<body>
  <h1>文字数カウンター発展編</h1>

  <label for="textInput">テキストを入力してください:</label><br>
  <textarea
    id="textInput"
    rows="4"
    cols="40"
    placeholder="ここにテキストを入力します"
  ></textarea>

  <p id="counter">現在の文字数:0文字</p>
  <p id="remaining">残り文字数:100文字</p>
  <p id="warningMessage"></p>

  <button id="submitButton">送信</button>

  <script>
    const textInputElement = document.getElementById('textInput');
    const counterElement = document.getElementById('counter');
    const remainingElement = document.getElementById('remaining');
    const warningMessageElement = document.getElementById('warningMessage');
    const submitButtonElement = document.getElementById('submitButton');

    const MAX_LENGTH = 100;

    function updateCounterState() {
      const currentText = textInputElement.value;
      const currentLength = currentText.length;
      const remainingLength = MAX_LENGTH - currentLength;

      counterElement.textContent = `現在の文字数:${currentLength}文字`;

      if (remainingLength >= 0) {
        remainingElement.textContent = `残り文字数:${remainingLength}文字`;
      } else {
        remainingElement.textContent = `残り文字数:0文字(${-remainingLength}文字オーバー)`;
      }

      if (currentLength > MAX_LENGTH) {
        warningMessageElement.textContent = `最大文字数(${MAX_LENGTH}文字)を超えています。`;
        warningMessageElement.classList.add('warning');

        submitButtonElement.disabled = true;
        submitButtonElement.classList.add('disabled');
      } else {
        warningMessageElement.textContent = '';
        warningMessageElement.classList.remove('warning');

        submitButtonElement.disabled = false;
        submitButtonElement.classList.remove('disabled');
      }
    }

    textInputElement.addEventListener('input', function () {
      updateCounterState();
    });

    submitButtonElement.addEventListener('click', function () {
      const currentText = textInputElement.value;
      const currentLength = currentText.length;

      if (currentLength > MAX_LENGTH) {
        alert(`最大文字数(${MAX_LENGTH}文字)を超えているため、送信できません。`);
        return;
      }

      alert('送信しました:\n' + currentText);
    });

    // 初期状態を反映します
    updateCounterState();
  </script>
</body>
</html>

複数の入力欄に文字数カウンターを適用する

同じ仕組みを“再利用できる形”にする

実際のサービスでは、

  • タイトル(最大50文字)
  • 本文(最大500文字)

など、複数の入力欄に文字数制限があることが多いです。

そこで、 「1つの入力欄に対して文字数カウンターをセットアップする関数」 を作ると、再利用しやすくなります。

function setupLengthCounter(options) {
  const {
    inputElement,
    counterElement,
    remainingElement,
    warningElement,
    maxLength
  } = options;

  function updateState() {
    const text = inputElement.value;
    const length = text.length;
    const remaining = maxLength - length;

    counterElement.textContent = `現在の文字数:${length}文字`;

    if (remaining >= 0) {
      remainingElement.textContent = `残り文字数:${remaining}文字`;
    } else {
      remainingElement.textContent = `残り文字数:0文字(${-remaining}文字オーバー)`;
    }

    if (length > maxLength) {
      warningElement.textContent = `最大文字数(${maxLength}文字)を超えています。`;
      warningElement.classList.add('warning');
    } else {
      warningElement.textContent = '';
      warningElement.classList.remove('warning');
    }
  }

  inputElement.addEventListener('input', updateState);
  updateState();
}
JavaScript

このようにしておくと、

setupLengthCounter({
  inputElement: document.getElementById('titleInput'),
  counterElement: document.getElementById('titleCounter'),
  remainingElement: document.getElementById('titleRemaining'),
  warningElement: document.getElementById('titleWarning'),
  maxLength: 50
});

setupLengthCounter({
  inputElement: document.getElementById('bodyInput'),
  counterElement: document.getElementById('bodyCounter'),
  remainingElement: document.getElementById('bodyRemaining'),
  warningElement: document.getElementById('bodyWarning'),
  maxLength: 500
});
JavaScript

のように、 異なる入力欄に同じロジックを簡単に適用できるようになります。

セキュリティ・ユーザー体験の視点からのまとめ

セキュリティの基本を守る

文字数カウンターのようなUIでも、 次の点を守ることが重要です。

  • ユーザー入力を画面に表示するときは、必ず textContent を使う
    • innerHTML を使うと、入力された文字列がHTMLとして解釈されてしまい、 <script> などが実行される危険があります。
  • フロント側の制限(最大文字数など)は、 バックエンド側でも必ず再チェックする必要があります。

ユーザー体験を意識した設計

  • 残り文字数やオーバーした文字数を表示することで、 ユーザーは「どこまで書けるか」を安心して把握できます。
  • 送信ボタンを無効化するだけでなく、 なぜ無効なのかを警告メッセージで伝えることが大切です。
  • 初期状態から正しい情報を表示しておくことで、 フォーム全体の信頼感が高まります。

Day 41 後半 練習用テンプレート

最後に、今日の内容をそのまま試せる練習用テンプレートを紹介します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 41 後半:文字数カウンター 総合練習テンプレート</title>
  <style>
    .warning {
      color: red;
      font-weight: bold;
    }
    .disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }
  </style>
</head>
<body>
  <h1>文字数カウンター 総合練習</h1>

  <textarea id="textInput" rows="4" cols="40" placeholder="テキストを入力"></textarea>
  <p id="counter">現在の文字数:0文字</p>
  <p id="remaining">残り文字数:100文字</p>
  <p id="warningMessage"></p>
  <button id="submitButton">送信</button>

  <script>
    console.log('--- 文字数カウンター 総合練習開始 ---');

    const textInputElement = document.getElementById('textInput');
    const counterElement = document.getElementById('counter');
    const remainingElement = document.getElementById('remaining');
    const warningMessageElement = document.getElementById('warningMessage');
    const submitButtonElement = document.getElementById('submitButton');

    const MAX_LENGTH = 100;

    function updateCounterState() {
      const text = textInputElement.value;
      const length = text.length;
      const remaining = MAX_LENGTH - length;

      counterElement.textContent = `現在の文字数:${length}文字`;

      if (remaining >= 0) {
        remainingElement.textContent = `残り文字数:${remaining}文字`;
      } else {
        remainingElement.textContent = `残り文字数:0文字(${-remaining}文字オーバー)`;
      }

      if (length > MAX_LENGTH) {
        warningMessageElement.textContent = `最大文字数(${MAX_LENGTH}文字)を超えています。`;
        warningMessageElement.classList.add('warning');
        submitButtonElement.disabled = true;
        submitButtonElement.classList.add('disabled');
      } else {
        warningMessageElement.textContent = '';
        warningMessageElement.classList.remove('warning');
        submitButtonElement.disabled = false;
        submitButtonElement.classList.remove('disabled');
      }
    }

    textInputElement.addEventListener('input', updateCounterState);

    submitButtonElement.addEventListener('click', () => {
      const text = textInputElement.value;
      const length = text.length;

      if (length > MAX_LENGTH) {
        alert(`最大文字数(${MAX_LENGTH}文字)を超えているため、送信できません。`);
        return;
      }

      alert('送信しました:\n' + text);
    });

    updateCounterState();

    console.log('--- 文字数カウンター 総合練習テンプレートの準備が完了しました ---');
  </script>
</body>
</html>

Day 41 後半のまとめ

Day 41後半では、

  • 文字数カウンターを「現在の文字数+残り文字数+警告+ボタン制御」という、 実用的な形に発展させたこと。
  • 状態更新の中心となる関数を作り、 DOM操作を整理して読みやすくしたこと。
  • 最大文字数を超えたときに、 見た目と機能の両方からユーザーに制限を伝える設計を体験したこと。
  • セキュリティとユーザー体験の両方を意識しながら、 フォームUIを作る感覚を育てたこと。

を整理しました。

この文字数カウンターは、 SNS投稿フォーム、コメント欄、問い合わせフォームなど、 多くの場面でそのまま応用できるパターンです。

ここまで来た皆さんは、 「DOMを操作して、ユーザーの体験を形にする」 という感覚を、かなり自分のものにし始めています。

タイトルとURLをコピーしました