JavaScript:イベント(クリック・入力・フォームを扱う)
音声
目次
addEventListenerの基本
addEventListenerでDOM要素にイベントを付けて、クリック・入力・送信を扱えるようにしましょう。
addEventListenerは要素に対して複数の処理を安全に追加でき、既存のonclickを上書きしない点が便利です。イベントハンドラは第一引数にイベント名、第二引数にコールバック関数を渡します。
CodePenの場合はHTML欄に要素、JS欄にスクリプトを置くと簡単に試せます。
貼り付け場所:CodePenを想定する場合はHTML欄に必要なタグ(下のHTMLブロック)を、JS欄にJavaScriptコードを貼ってください。
最小コード:
<!-- HTML欄:CodePenのHTMLに貼ります -->
<form id="myForm">
<input id="name" name="name" placeholder="名前を入力" />
<button id="submitBtn" type="submit">送信</button>
</form>
<div id="out"></div>
<button id="btn">単独ボタン</button>
<div id="container">
<button class="child">子ボタン</button>
</div>
// JS欄
// まず「使うDOM」を取って変数に入れる(毎回探すより読みやすい)
const form = document.getElementById('myForm'); // form全体
const nameInput = document.getElementById('name'); // 名前入力欄
const out = document.getElementById('out'); // 表示先(メッセージ欄)
const submitBtn = document.getElementById('submitBtn'); // 送信ボタン
// 入力中(キー入力のたび)に、今の内容を画面に出す
nameInput.addEventListener('input', () => {
out.textContent = `入力中: ${nameInput.value}`; // value が入力欄の中身
});
// 送信ボタン or Enterでフォーム送信されたときの処理
form.addEventListener('submit', (e) => {
e.preventDefault(); // 本来の「ページ遷移して送信」を止めて、JSで処理する
// 空文字やスペースだけはNGにしたいので trim() で前後スペースを除く
if (!nameInput.value.trim()) {
out.textContent = '名前を入力してください'; // エラー表示
return; // ここで終了(下の「送信した」処理はしない)
}
submitBtn.disabled = true; // 連打で二重送信しないようにボタンを無効化(簡易)
out.textContent = `送信しました: ${nameInput.value}`; // 成功メッセージ
});
click/input/submitの使いどころ
clickは任意の要素の押下検知に向いています。inputはテキスト入力の変更を逐次扱う時に使い、submitはフォーム全体の検証と送信処理に適しています。
たとえばエンターで送る場合はsubmitにまとめると自然です。inputでリアルタイムなフィードバックを出し、submitで最終チェックとサーバ送信処理をする使い分けが一般的です。
実行方法:CodePenのRunボタン、あるいはブラウザでHTMLを開いてJSを読み込むことで動作します(CodePenならJS欄を貼って実行するだけです)。
フォーム値の取り出しと検証
フォーム値は要素のvalueプロパティから安全に取り出します。必須チェックはtrimで空白だけの入力を弾くのが基本で、HTMLのrequired属性やConstraint Validation APIを併用するとアクセシビリティが向上します。カスタム検証では正規表現でパターンをチェックし、エラーメッセージを画面に出すとユーザーが理解しやすくなります。
確認方法:画面の#outに表示されるメッセージとブラウザのConsoleログで期待通りかを確認してください(Console.logを追加すると詳細が見えます)。
イベント伝播(バブリング)を軽く理解
子要素で発生したイベントは親要素へ伝わる(バブリング)仕様です。親で一括処理するイベント委譲(イベントデリゲーション)は大量の同種要素に対して有効です。
一方、子の処理だけで止めたい場合はevent.stopPropagation()で伝播を止めます。下の応用コードでcontainerにclickを付け、どの子が押されたか判定する例を示します。
// 応用:イベント委譲と伝播の例(JS欄に追記して試してください)
// 親要素(container)に「まとめて」clickを付ける:これがイベント委譲
const container = document.getElementById('container');
container.addEventListener('click', (e) => {
// e.target は「実際にクリックされた要素」(ここでは button.child など)
const target = e.target;
// クリックされた要素が .child を持っているなら「子ボタン」と判断する
if (target.classList.contains('child')) {
out.textContent = '子ボタンが押されました';
}
// ※ポイント:
// 子ボタンに直接 addEventListener しなくても、
// 親(container)1つで子ボタンのクリックを拾える
// (子ボタンが増えてもコードを増やさなくてよい)
});
// 「単独ボタン」には直接 click を付ける(委譲ではなく通常の付け方)
document.getElementById('btn').addEventListener('click', (e) => {
// click は「子 → 親 → document…」の順で上に伝わる(バブリング)
// ここで止めると、上の親ハンドラ(container側など)に届かない
e.stopPropagation(); // 親に伝播させたくない時
out.textContent = '単独ボタンが押されました';
});
使い分けの基準として、複数の似た要素のイベントは親にまとめる(委譲)とコードがシンプルになります。個別に異なる振る舞いが必要なら、個別にaddEventListenerを付けると分かりやすくなります。
二重送信や連打への対策
送信ボタンをdisabledにして送信中フラグを立て、サーバ側でも同一リクエストの重複を検出するのが安全な組み合わせです。
UIでは送信直後にボタンを無効化し、処理完了後に再度有効化するなどユーザーの操作感を保ちます。
短時間の連打を抑えるには、タイムアウトで再有効化する方法も有用です。
よくあるミスとして、スクリプトをHTMLの<head>に置いてDOM要素が存在しない状態でquerySelectorを呼ぶとnullになり、イベントが付かないことが多いです。
直し方は<script>を</body>直前に置くか、DOMContentLoadedで待つことです。
注意(ここだけ)
submitはページ遷移するので、SPA風に扱うならevent.preventDefault()が必要です。入力イベントは連発します。重い処理を入れるなら、軽い検証だけにするか、間引き(debounce)を検討します。
連打で二重実行が起きるなら、ボタンを一時的にdisabledにするなど「再入防止」を入れます。
要約
addEventListenerは複数のハンドラを安全に追加でき、CodePenのJS欄で試せます。
clickは任意要素、inputは逐次入力、submitはフォーム全体で使い分けます。
フォーム値はvalueで取得し、trimや正規表現で検証すると堅牢になります。
イベントはバブリングするため、委譲やstopPropagationで制御できます。
二重送信はUI側(disabledやフラグ)とサーバ側の両方で対策すると安全です。