はじめに
この記事を読めば、JavaScriptでイベントハンドラを使ってさまざまなアクションを実装することができるようになります。
イベントハンドラを用いてWebページのインタラクションを向上させることで、より魅力的なコンテンツを作成できるでしょう。
この記事では、イベントハンドラの基本的な使い方から応用例、カスタマイズ方法まで、初心者目線で徹底解説しています。
また、実践的なサンプルコード20選を用意しましたので、ぜひ参考にしてください。
●イベントハンドラとは
イベントハンドラとは、JavaScriptでイベント(ユーザーがWebページで何らかの操作を行った際に発生するアクション)が発生したときに、特定の処理を実行するための関数です。
例えば、ボタンがクリックされたときや、フォームの入力が変更されたときなど、さまざまなイベントに対応して処理を実行することができます。
●イベントハンドラの使い方
ここでは、イベントハンドラの基本的な使い方を3つのサンプルコードで解説します。
○サンプルコード1:クリックイベント
下記のサンプルコードでは、ボタンがクリックされたときにアラートが表示されるようになっています。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>クリックイベントの例</title>
</head>
<body>
<button id="myButton">クリックしてください</button>
<script>
document.getElementById("myButton").onclick = function() {
alert("ボタンがクリックされました!");
};
</script>
</body>
</html>
○サンプルコード2:マウスオーバーイベント
下記のサンプルコードでは、マウスが要素の上に乗ったとき(マウスオーバー)に、要素の背景色が変わるようになっています。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>マウスオーバーイベントの例</title>
<style>
#myElement {
width: 100px;
height: 100px;
background-color: lightblue;
}
</style>
</head>
<body>
<div id="myElement"></div>
<script>
document.getElementById("myElement").onmouseover = function() {
this.style.backgroundColor = "orange";
};
document.getElementById("myElement").onmouseout = function() {
this.style.backgroundColor = "lightblue";
};
</script>
</body>
</html>
○サンプルコード3:キーボードイベント
下記のサンプルコードでは、テキストボックスに入力された文字が大文字であるかどうかを判定し、大文字の場合はアラートを表示します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>キーボードイベントの例</title>
</head>
<body>
<input type="text" id="myInput" placeholder="テキストを入力してください">
<script>
document.getElementById("myInput").onkeyup = function(event) {
if (event.key === event.key.toUpperCase() && event.key !== event.key.toLowerCase()) {
alert("大文字が入力されました!");
}
};
</script>
</body>
</html>
●イベントハンドラの応用例
ここでは、イベントハンドラを用いた応用例を7つのサンプルコードで解説します。
○サンプルコード4:フォームバリデーション
下記のサンプルコードでは、フォームの送信ボタンがクリックされたときに、入力内容が正しいかどうかをチェックします。
入力内容が正しくない場合は、アラートでエラーメッセージが表示されます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>フォームバリデーションの例</title>
</head>
<body>
<form id="myForm">
<label for="email">メールアドレス:</label>
<input type="email" id="email" required>
<button type="submit">送信</button>
</form>
<script>
document.getElementById("myForm").onsubmit = function(event) {
event.preventDefault();
const email = document.getElementById("email").value;
if (!email.includes("@")) {
alert("メールアドレスが正しくありません");
} else {
alert("フォームが正常に送信されました");
}
};
</script>
</body>
</html>
○サンプルコード5:ドラッグアンドドロップ
下記のサンプルコードでは、ドラッグアンドドロップを使って、要素を別の場所に移動させることができます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ドラッグアンドドロップの例</title>
<style>
#dragArea {
width: 500px;
height: 300px;
border: 1px solid #ccc;
position: relative;
}
.draggable {
width: 50px;
height: 50px;
background-color: lightblue;
position: absolute;
cursor: grab;
}
</style>
</head>
<body>
<div id="dragArea">
<div class="draggable" id="myElement"></div>
</div>
<script>
let mouseX, mouseY;
let offsetX, offsetY;
let isDragging = false;
const myElement = document.getElementById("myElement");
myElement.onmousedown = function(event) {
isDragging = true;
offsetX = event.clientX - this.offsetLeft;
offsetY = event.clientY - this.offsetTop;
};
document.onmousemove = function(event) {
if (isDragging) {
mouseX = event.clientX - offsetX;
mouseY = event.clientY - offsetY;
myElement.style.left = mouseX + "px";
myElement.style.top = mouseY + "px";
}
};
document.onmouseup = function() {
isDragging = false;
};
</script>
</body>
</html>
○サンプルコード6:スライダー
下記のサンプルコードでは、スライダーを作成して、スライドを切り替えることができます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>スライダーの例</title>
<style>
#slider {
width: 300px;
height: 200px;
overflow: hidden;
position: relative;
}
.slide {
width: 300px;
height: 200px;
position: absolute;
transition: left 0.5s;
}
.slide img {
width: 100%;
height: auto;
}
</style>
</head>
<body>
<div id="slider">
<div class="slide" style="left: 0;"><img src="image1.jpg" alt="スライド1"></div>
<div class="slide" style="left: 100%;"><img src="image2.jpg" alt="スライド2"></div>
<div class="slide" style="left: 200%;"><img src="image3.jpg" alt="スライド3"></div>
</div>
<button id="prev">前へ</button>
<button id="next">次へ</button>
<script>
const slides = document.querySelectorAll(".slide");
let currentSlide = 0;
document.getElementById("prev").onclick = function() {
if (currentSlide > 0) {
currentSlide--;
} else {
currentSlide = slides.length - 1;
}
updateSlides();
};
document.getElementById("next").onclick = function() {
if (currentSlide < slides.length - 1) {
currentSlide++;
} else {
currentSlide = 0;
}
updateSlides();
};
function updateSlides() {
for (let i = 0; i < slides.length; i++) {
slides[i].style.left = (i - currentSlide) * 100 + "%";
}
}
</script>
</body>
</html>
○サンプルコード7:モーダルウィンドウ
下記のサンプルコードでは、ボタンをクリックするとモーダルウィンドウが表示され、閉じるボタンや背景をクリックすると閉じることができます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>モーダルウィンドウの例</title>
<style>
.modal {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;
border-radius: 5px;
z-index: 10;
}
.modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 5;
}
</style>
</head>
<body>
<button id="openModal">モーダルを開く</button>
<div class="modal" id="myModal">
<h2>モーダルウィンドウ</h2>
<p>これはモーダルウィンドウのコンテンツです。</p>
<button id="closeModal">閉じる</button>
</div>
<div class="modal-overlay" id="modalOverlay"></div>
<script>
document.getElementById("openModal").onclick = function() {
document.getElementById("myModal").style.display = "block";
document.getElementById("modalOverlay").style.display = "block";
};
document.getElementById("closeModal").onclick = function() {
document.getElementById("myModal").style.display = "none";
document.getElementById("modalOverlay").style.display = "none";
};
document.getElementById("modalOverlay").onclick = function() {
document.getElementById("myModal").style.display = "none";
document.getElementById("modalOverlay").style.display = "none";
};
</script>
</body>
</html>
○サンプルコード8:アコーディオンメニュー
下記のサンプルコードでは、クリックするとアコーディオンメニューが開閉する機能を実装しています。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>アコーディオンメニューの例</title>
<style>
.accordion {
cursor: pointer;
}
.panel {
display: none;
}
</style>
</head>
<body>
<h2 class="accordion">アコーディオン1</h2>
<div class="panel">
<p>アコーディオン1のコンテンツです。</p>
</div>
<h2 class="accordion">アコーディオン2</h2>
<div class="panel">
<p>アコーディオン2のコンテンツです。</p>
</div>
<h2 class="accordion">アコーディオン3</h2>
<div class="panel">
<p>アコーディオン3のコンテンツです。</p>
</div>
<script>
const accordions = document.querySelectorAll(".accordion");
for (const accordion of accordions) {
accordion.onclick = function () {
this.nextElementSibling.style.display = this.nextElementSibling.style.display === "block" ? "none" : "block";
};
}
</script>
</body>
</html>
○サンプルコード9:タブ切り替え
下記のサンプルコードでは、タブをクリックすると表示されるコンテンツが切り替わる機能を実装しています。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>タブ切り替えの例</title>
<style>
.tab {
cursor: pointer;
}
.tab-content {
display: none;
}
.active {
display: block;
}
</style>
</head>
<body>
<div>
<div class="tab" id="tab1">タブ1</div>
<div class="tab" id="tab2">タブ2</div>
<div class="tab" id="tab3">タブ3</div>
</div>
<div>
<div class="tab-content active" id="content1">
<p>タブ1のコンテンツです。</p>
</div>
<div class="tab-content" id="content2">
<p>タブ2のコンテンツです。</p>
</div>
<div class="tab-content" id="content3">
<p>タブ3のコンテンツです。</p>
</div>
</div>
<script>
const tabs = document.querySelectorAll(".tab");
const contents = document.querySelectorAll(".tab-content");
for (const tab of tabs) {
tab.onclick = function () {
document.querySelector(".tab-content.active").classList.remove("active");
const contentId = this.id.replace("tab", "content");
document.getElementById(contentId).classList.add("active");
};
}
</script>
</body>
</html>
○サンプルコード10:インクリメンタルサーチ
下記のサンプルコードでは、入力内容に応じてリアルタイムで検索結果が表示されるインクリメンタルサーチを実装しています。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>インクリメンタルサーチの例</title>
<style>
.search-results {
display: none;
}
</style>
</head>
<body>
<input type="text" id="search" placeholder="検索...">
<div class="search-results" id="searchResults"></div>
<script>
const search = document.getElementById("search");
const searchResults = document.getElementById("searchResults");
const data = [
"Apple",
"Banana",
"Cherry",
"Grape",
"Lemon",
"Orange",
"Pineapple",
"Strawberry",
];
search.addEventListener("input", () => {
const searchTerm = search.value.trim().toLowerCase();
searchResults.innerHTML = "";
if (searchTerm) {
searchResults.style.display = "block";
const filteredData = data.filter(item => item.toLowerCase().includes(searchTerm));
for (const item of filteredData) {
const result = document.createElement("div");
result.textContent = item;
searchResults.appendChild(result);
}
} else {
searchResults.style.display = "none";
}
});
</script>
</body>
</html>
●注意点と対処法
イベントハンドラを使用する際には、いくつかの注意点と対処法があります。
例えば、ブラウザ間のイベントの違いや、イベントバブリングとキャプチャリングの違い、そしてメモリリークを防ぐためのイベントハンドラの削除などが挙げられます。
これらの問題に対処するために、適切なイベントリスナーの登録・削除や、イベントオブジェクトの正確な取得が重要です。
●カスタマイズ方法
イベントハンドラをカスタマイズすることで、様々なアプリケーションやウェブページでのユーザーエクスペリエンスを向上させることができます。
ここでは、カスタムイベントの作成やイベントデリゲーション、イベントの停止と再開、イベントハンドラの動的追加・削除、非同期処理とイベントハンドラ、画像プリロード、スムーズスクロール、スクロールイベントとアニメーション、リサイズイベントとレスポンシブデザイン、トグルボタンなど、様々なカスタマイズ方法が紹介されています。
○サンプルコード11:カスタムイベント
JavaScriptでは、カスタムイベントを作成して発火させることができます。
これにより、特定のアクションや状況に応じてイベントを発生させることが可能になります。
下記は、カスタムイベントの作成と発火の例です。
// カスタムイベントの作成
const customEvent = new CustomEvent("customAction", {
detail: {
message: "カスタムイベントが発生しました"
}
});
// カスタムイベントのリスナーを追加
document.addEventListener("customAction", (event) => {
console.log(event.detail.message);
});
// カスタムイベントを発火
document.dispatchEvent(customEvent);
この例では、”customAction”という名前のカスタムイベントを作成し、リスナーを追加しています。その後、dispatchEvent
メソッドを使ってカスタムイベントを発火させています。
このイベントが発火されると、リスナーが実行され、コンソールにメッセージが表示されます。
○サンプルコード12:イベントデリゲーション
イベントデリゲーションは、イベントハンドラを親要素に設定し、子要素で発生したイベントを捕捉して処理する方法です。
これにより、動的に追加された要素に対してもイベントが適用されるため、リソースの節約につながります。下記は、イベントデリゲーションの例です。
<ul id="itemList">
<li>アイテム1</li>
<li>アイテム2</li>
<li>アイテム3</li>
</ul>
const itemList = document.getElementById("itemList");
// 親要素にイベントハンドラを設定
itemList.addEventListener("click", (event) => {
if (event.target.tagName === "LI") {
console.log("クリックされたアイテム: ", event.target.textContent);
}
});
この例では、<ul>
要素にイベントハンドラを設定しています。
<li>
要素がクリックされると、イベントが親要素まで伝播し、親要素のイベントハンドラが実行されます。
この際、event.target
を使ってクリックされた要素を判別し、処理を行っています。
○サンプルコード13:イベントの停止と再開
イベントの伝播を制御する方法として、イベントの停止(stopPropagation)と再開があります。
下記は、イベントの停止と再開の例です。
HTML
<button id="startButton">スタート</button>
<button id="stopButton">ストップ</button>
<div id="box"></div>
JavaScript
const startButton = document.getElementById("startButton");
const stopButton = document.getElementById("stopButton");
const box = document.getElementById("box");
let isStopped = false;
startButton.addEventListener("click", () => {
if (!isStopped) {
box.classList.add("animate");
}
});
stopButton.addEventListener("click", () => {
if (!isStopped) {
isStopped = true;
box.classList.remove("animate");
} else {
isStopped = false;
box.classList.add("animate");
}
});
この例では、スタートボタンがクリックされると、box
要素にアニメーションが適用されます。
ストップボタンがクリックされると、isStopped
変数の状態に応じてアニメーションが停止または再開されます。
このように、イベントハンドラ内で条件分岐を行い、イベントの停止と再開を制御することができます。
○サンプルコード14:イベントハンドラの動的追加・削除
イベントハンドラは、必要に応じて動的に追加や削除が可能です。
下記は、イベントハンドラの動的追加と削除の例です。
HTML
<button id="toggleButton">イベントハンドラの追加・削除</button>
<div id="box"></div>
JavaScript
const toggleButton = document.getElementById("toggleButton");
const box = document.getElementById("box");
let isEventHandlerAttached = false;
function boxClickHandler() {
alert("クリックされました!");
}
toggleButton.addEventListener("click", () => {
if (!isEventHandlerAttached) {
box.addEventListener("click", boxClickHandler);
isEventHandlerAttached = true;
} else {
box.removeEventListener("click", boxClickHandler);
isEventHandlerAttached = false;
}
});
この例では、toggleButton
がクリックされる度に、box
要素へのクリックイベントハンドラが追加または削除されます。
イベントハンドラを追加するにはaddEventListener
メソッドを使用し、削除するにはremoveEventListener
メソッドを使用します。
動的にイベントハンドラを追加・削除することで、ページ上の要素の振る舞いを柔軟に制御することができます。
○サンプルコード15:非同期処理とイベントハンドラ
イベントハンドラは非同期処理と組み合わせることもできます。
下記は、非同期処理を使用してAPIからデータを取得し、クリックイベントで表示を切り替える例です。
HTML
<button id="loadDataButton">データをロード</button>
<div id="content"></div>
JavaScript
const loadDataButton = document.getElementById("loadDataButton");
const content = document.getElementById("content");
async function fetchData() {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
return data;
}
loadDataButton.addEventListener("click", async () => {
content.textContent = "データをロード中...";
const data = await fetchData();
content.textContent = JSON.stringify(data, null, 2);
});
この例では、loadDataButton
がクリックされると、非同期処理によりAPIからデータを取得し、その結果をcontent
要素に表示します。
async
/ await
構文を使用して、非同期処理を簡潔に記述することができます。
イベントハンドラと非同期処理を組み合わせることで、ユーザーが操作したタイミングでデータを取得するなど、リアルタイムなUIの実現が可能になります。
○サンプルコード16:画像プリロード
画像プリロードは、画像を事前に読み込むことで、画像の表示が遅延するのを防ぐテクニックです。
イベントハンドラを使って、画像が完全に読み込まれたときに処理を行うことができます。
下記は、画像プリロードの例です。
HTML
<img id="preloadedImage" src="" style="display:none;">
<button id="showImage">画像を表示</button>
JavaScript
const preloadedImage = document.getElementById("preloadedImage");
const showImage = document.getElementById("showImage");
function preloadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = url;
img.onload = () => resolve(img);
img.onerror = () => reject(new Error("画像の読み込みに失敗しました"));
});
}
async function init() {
try {
const img = await preloadImage("https://example.com/image.jpg");
preloadedImage.src = img.src;
} catch (error) {
console.error(error);
}
}
init();
showImage.addEventListener("click", () => {
preloadedImage.style.display = "block";
});
この例では、preloadImage
関数で画像を非同期的にプリロードし、画像が読み込まれたときにPromiseを解決します。
init
関数では、プリロードした画像をpreloadedImage
要素のsrc
属性に設定しています。
showImage
ボタンがクリックされると、プリロードされた画像が表示されます。
画像プリロードにより、ユーザーが操作したタイミングで画像がすぐに表示されるようになります。
○サンプルコード17:スムーズスクロール
スムーズスクロールは、ページ内のリンクをクリックした際に滑らかにスクロールする機能です。
イベントハンドラを使ってスムーズスクロールを実装することができます。
下記は、スムーズスクロールの例です。
HTML
<a href="#section1" class="smooth-scroll">セクション1へ</a>
<a href="#section2" class="smooth-scroll">セクション2へ</a>
<div id="section1">セクション1の内容</div>
<div id="section2">セクション2の内容</div>
JavaScript
function smoothScroll(event) {
event.preventDefault();
const targetId = event.currentTarget.getAttribute("href");
const targetElement = document.querySelector(targetId);
const targetPosition = targetElement.getBoundingClientRect().top;
const startPosition = window.pageYOffset;
const distance = targetPosition - startPosition;
const duration = 1000;
let start = null;
function step(timestamp) {
if (!start) start = timestamp;
const progress = timestamp - start;
const currentPosition =
startPosition + distance * easeInOutQuad(progress / duration);
window.scrollTo(0, currentPosition);
if (progress < duration) {
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, startPosition + distance);
}
}
function easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
}
window.requestAnimationFrame(step);
}
document.querySelectorAll(".smooth-scroll").forEach((link) => {
link.addEventListener("click", smoothScroll);
});
この例では、smoothScroll
関数をクリックイベントのリスナーとして設定し、ページ内のリンクをクリックした際にスクロールアニメーションを実行します。
easeInOutQuad
関数は、アニメーションのイージング(加速と減速)を制御するための関数です。
スムーズスクロールを実装することで、ユーザーがページ内のリンクをクリックしたときにより快適な体験を提供できます。
○サンプルコード18:スクロールイベントとアニメーション
スクロールイベントを使用して、ユーザーがページをスクロールするとアニメーションを表示することができます。
下記は、スクロールイベントを利用したアニメーションの実装例です。
HTML
<div class="fade-in">スクロールでフェードインする要素</div>
CSS
.fade-in {
opacity: 0;
transition: opacity 1s;
}
.fade-in.visible {
opacity: 1;
}
JavaScript
function checkFadeInElements() {
const fadeInElements = document.querySelectorAll(".fade-in");
fadeInElements.forEach((element) => {
const rect = element.getBoundingClientRect();
const windowHeight = window.innerHeight;
if (rect.top <= windowHeight - 50) {
element.classList.add("visible");
} else {
element.classList.remove("visible");
}
});
}
window.addEventListener("scroll", checkFadeInElements);
window.addEventListener("load", checkFadeInElements);
この例では、.fade-in
クラスが付与された要素が画面に表示されると、フェードインアニメーションが実行されます。
checkFadeInElements
関数は、要素が表示されたかどうかを確認し、表示された場合に.visible
クラスを追加します。
このクラスが追加されることで、CSSのopacity
が変更され、フェードインアニメーションが実行されます。
このように、スクロールイベントを利用してアニメーションを実装することで、ユーザーの興味を引くエンゲージングなコンテンツを提供できます。
○サンプルコード19:リサイズイベントとレスポンシブデザイン
リサイズイベントは、ウィンドウのサイズが変更されたときに発生します。
これを利用して、レスポンシブデザインに対応した動的な処理を実装することができます。
下記は、リサイズイベントを利用してナビゲーションメニューの表示を切り替える例です。
HTML
<button id="menu-button">メニュー</button>
<nav id="navigation" class="hidden">
<ul>
<li>メニュー1</li>
<li>メニュー2</li>
<li>メニュー3</li>
</ul>
</nav>
CSS
.hidden {
display: none;
}
@media (min-width: 768px) {
#menu-button {
display: none;
}
#navigation {
display: block;
}
}
JavaScript
const menuButton = document.getElementById("menu-button");
const navigation = document.getElementById("navigation");
menuButton.addEventListener("click", () => {
navigation.classList.toggle("hidden");
});
window.addEventListener("resize", () => {
if (window.innerWidth >= 768) {
navigation.classList.remove("hidden");
} else {
navigation.classList.add("hidden");
}
});
この例では、ウィンドウの幅が768px以上の場合、ナビゲーションメニューが表示されます。
それ以外の場合、メニューボタンが表示され、クリックすることでナビゲーションメニューが表示されるようになっています。
リサイズイベントを利用して、ウィンドウの幅に応じてナビゲーションメニューの表示を切り替えることができます。
○サンプルコード20:トグルボタン
トグルボタンは、クリックすることで状態が切り替わるボタンです。
例えば、ダークモードとライトモードを切り替えるボタンが考えられます。
下記は、トグルボタンを実装するサンプルコードです。
HTML
<button id="toggle-button">ダークモード</button>
CSS
body.light-mode {
background-color: #ffffff;
color: #333333;
}
body.dark-mode {
background-color: #333333;
color: #ffffff;
}
JavaScript
const toggleButton = document.getElementById("toggle-button");
toggleButton.addEventListener("click", () => {
document.body.classList.toggle("dark-mode");
document.body.classList.toggle("light-mode");
if (document.body.classList.contains("dark-mode")) {
toggleButton.textContent = "ライトモード";
} else {
toggleButton.textContent = "ダークモード";
}
});
// 初期状態
document.body.classList.add("light-mode");
この例では、トグルボタンをクリックすることで、ダークモードとライトモードが切り替わります。
ボタンのテキストも状態に応じて変更されます。
まとめ
イベントハンドラを使用することで、様々なインタラクティブな機能を実装できます。
この記事では、イベントハンドラの基本的な使い方や応用例、カスタマイズ方法を紹介しました。
これらの知識を活かして、ユーザーエクスペリエンスを向上させるWebアプリケーションを作成してみてください。