11. イベントの基本

イベント

イベントとは

「マウスをクリックした」「キーボードを入力した」「HTMLの読み込みが完了した」といったように、ブラウザで何か操作や動作が発生したことをイベント(Event) といいます。

Event Listener(イベントリスナー)

Event Listener(イベントリスナー)は、特定のイベント(クリックやキー押下など)を監視する仕組みです。

addEventListener()

addEventListener() によって、複数のイベントリスナーを1つの要素に登録することが可能で、イベント伝播のフェーズ(キャプチャリングまたはバブリング)を指定することもできます。

Event Handler(イベントハンドラ)

Event Handler(イベントハンドラ)は、イベントが発生したときに実際に実行される関数のことです。イベントリスナーが特定のイベントを「リッスン」しているのに対し、イベントハンドラーはそのイベントが発生した際に呼び出される関数です。

イベント名の種類

イベント名は、クリックや読み込みなどをプログラムのキーにしたもので、以下はよく利用されるイベント名の一覧です。

イベント名(JS) (HTML) 説明
load onload ページが読み込まれたとき
click onclick クリックされたとき
dblclick ondblclick ダブルクリックされたとき
load onload ページが読み込まれたとき
input onload 値が入力されたとき
submit onsubmit submitボタンが押されたとき
change onchange 内容が変更されたとき
keypress onkeypress キーボードキーが押されたとき
focus onfocus ターゲットが選択された時
mouseup onmouseup ターゲット内でマウスをアップしたとき
mouseover onmouseover マウスカーソルがターゲットの中に入ったとき
mousemove onmousemove マウスカーソルがターゲットの中に移動したとき
drag ondrag ドラッグされたとき
scroll onscroll スクロール位置が変更されたとき

他にもまだあるので、必要になった時に調べてみてもよいでしょう。

イベント登録方法

イベントの登録方法は大きく2つあります。

  • HTMLタグで設定
  • addEventListener()

ここでは、HTMLタグにイベントを登録する方法を説明します。

onclick

onclickは、HTML要素がクリックされたときに、イベントが発生します。

<button onclick="JSの処理">Click<button>

<a onclick="JSの処理">Click</a>

onmouseover

onmouseoverは、HTML要素内にマウスが入ったときに、イベントが発生します。

<div onmouseover="JS処理">
マウスオーバーの領域
</div>

onchange

onchangeは、値が変更されたときに、イベントが発生します。

<input type="text" onchange="JS処理">

keydown

keydown キーボードのキーが押されるたびに、イベントが発生します。

<body onkeydown="JSの処理">

</body>

サイコロアプリ

ファイル構成

basic/
├── css/
│      └── dice2.css
├── js/
│      └── dice2.js
└── dice2.html
dice2.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Dice Roll</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link rel="stylesheet" href="css/dice2.css">
</head>

<body class="bg-gray-100">

  <nav class="text-center p-8 bg-white">
    <h2 id="title" class="text-3xl font-bold mb-4"></h2>
    <div id="message" class="text-md p-3"></div>
  </nav>

  <main class="flex flex-col items-center mt-10 min-h-screen">
    <div id="dice" class="w-[150px] h-[150px] text-center p-[50px] bg-white shadow-lg rounded-lg">
      <p id="result" data-number="" class="text-5xl font-bold text-blue-600"></p>
    </div>

    <!-- サイコロを振るボタン -->
    <button onclick="rollDice()" id="rollButton" class="mt-6 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
      サイコロを振る
    </button>
  </main>

  <script src="js/dice2.js"></script>
</body>

</html>
js/dice2.js
// タイトルの設定
var titleElement = document.getElementById("title");
var messageElement = document.getElementById("message");
var diceElement = document.getElementById("dice");
var number = 1;

// タイトルと初期メッセージの設定
titleElement.innerText = 'DICE';
messageElement.innerHTML = 'サイコロをふってください!';

/**
 * ランダムな整数を生成
 */
const randomNumber = (min, max) => {
    return Math.floor(Math.random() * (max + 1 - min)) + min;
};

/**
 * サイコロの画像を切り替える関数
 */
const updateDiceImage = (number) => {
    var resultElement = document.getElementById("result");
    resultElement.src = `./images/dice${number}.png`;
};

クリックイベント

buttonタグ確認

button(サイコロを振るボタン)がクリックされると、rollDice() 実行されるようになっています。

dice2.html
    <!-- サイコロを振るボタン -->
    <button onclick="rollDice()" id="rollButton" class="mt-6 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
      サイコロを振る
    </button>

関数定義

JSファイルに rollDice() を定義して、コンソール表示します。

js/dice2.js
/**
 * サイコロを振る関数
 */
const rollDice = () => {
    console.log("Click!")
};

動作確認

ボタンをクリックするとコンソール表示さることを確認します。

コンソール

サイコロの更新

updateDiceImage() では、imgタグのサイコロ画像が number によって変更します。

dice2.html
    <div id="dice" class="">
      <img id="result" src="./images/dice1.png" alt="Dice" class="w-[150px]">
    </div>
js/dice2.js
const updateDiceImage = (number) => {
    var resultElement = document.getElementById("result");
    // 画像のパスを変更
    resultElement.src = `./images/dice${number}.png`;
};

クリックでサイコロ画像変更

rollDice() で、1 から 6 のランダムな数字を取得し、サイコロ画像を更新します。

js/dice2.js
const rollDice = () => {
    console.log("Click!");
    // 1 - 6 のランダムな数字
    number = randomNumber(1, 6);
    // サイコロ画像を更新
    updateDiceImage(number);
}

ボタンクリックで確認

ボタンクリックするたびに、サイコロの画像が変わるか確認します。

タイマー

setInterval()

setInterval()一定の時間(ms)間隔で繰り返し処理ができます。

setInterval(処理, 時間)

時間間隔の設定

処理はコールバック関数の形式で記述し、時間は 1秒 = 1000 となる数値で設定します。

無名関数
setInterval(function () {
	//処理
}, 1000)
アロー関数
setInterval(() => {
	//処理
}, 1000)

タイマーID

setInterval() の戻り値はタイマーIDとして利用できます。例えばタイマーを止めるときにタイマーIDを利用します。

//タイマーID:timer
const timer = setInterval(function () {
	//処理
}, 1000)

Set Interval スニペット

setInterval() のコーディングは、Set Interval Functionスニペットを利用すると便利です。

clearInterval()

clearInterval() は実行しているタイマー処理を終了します。setInterval() で設定した変数のタイマーIDが必要です。

clearInterval(timer)

サイコロアニメーション

setInterval() で、0.05秒間隔でサイコロ画像を変更します。

js/dice2.js
const rollDice = () => {
    console.log("Click!");

    // サイコロが振られている間、画像をランダムに変更(0.05秒インターバル)
    const interval = setInterval(() => {
        number = randomNumber(1, 6);
        updateDiceImage(number);
    }, 50);
}

動作確認

ボタンをクリックすると、サイコロがランダムに変更します。

  • タイマー停止がないため、永久に画像が変更します。

setTimeout()

setTimeout()指定時間(ms)後に処理します。

setTimeout(処理, 時間)

時間の設定

処理はコールバック関数の形式で記述し、時間は 1秒 = 1000 となる数値で設定します。

無名関数
setTimeout(function () {
	//処理
}, 1000)
アロー関数
setTimeout(() => {
	//処理
}, 1000)

Set Timeout スニペット

setTimeout() のコーディングは、Set Timeout Functionスニペットを利用すると便利です。

サイコロ停止

setTimeout() を追加し、2秒後に clearInterval() でタイマーを停止します。また、メッセージも変更しておきます。

js/dice2.js
const rollDice = () => {
    console.log("Click!");

    const timer = setInterval(() => {
        number = randomNumber(1, 6);
        updateDiceImage(number);
    }, 50); 

    // 2秒後にサイコロを止める
    setTimeout(() => {
        // タイマー停止
        clearInterval(timer);

        // メッセージ更新
        messageElement.innerHTML = "サイコロをふりました!";
    }, 2000);
};

動作確認

サイコロが2秒後にサイコロが停止し、メッセージが変更します。

アニメーション

「dice2.css」の .rolling でアニメーションを反映させます。

CSSアニメーション

「dice2.css」にアニメーションを追加します。

css/dice2.css
/* サイコロが振られているように見せるアニメーション */
@keyframes diceRoll {
    0% {
        transform: rotate(0deg);
    }

    25% {
        transform: rotate(90deg);
    }

    50% {
        transform: rotate(180deg);
    }

    75% {
        transform: rotate(270deg);
    }

    100% {
        transform: rotate(360deg);
    }
}

.rolling {
    animation: diceRoll 0.6s ease-in-out infinite;
}

アニメーション開始・終了

サイコロ要素のクラスに、「rolling」を追加・削除して、アニメーションを開始・終了します。

js/dice2.js
const rollDice = () => {
    console.log("Click!");

    const interval = setInterval(() => {
        number = randomNumber(1, 6);
        updateDiceImage(number);
    }, 50); 

    // アニメーション開始
    diceElement.classList.add("rolling");

    setTimeout(() => {
        clearInterval(interval);
        // アニメーション終了
        diceElement.classList.remove("rolling");
        messageElement.innerHTML = "サイコロをふりました!";
    }, 2000);
};

動作確認

CSSアニメーションが追加されました。

ウィンドウ読み込み

JSの実行タイミング

通常のJSは scriptタグやJSファイルが読み込まれた時点で実行されます。よって、HTMLタグが読み込み前にプログラムが実行され、エラーになる可能性があります。

<html>
<head>

</head>
<body>
    <!-- ここに記述するとHTMLタグが読み込み前にプログラムが実行される -->
    <script src="js/main.js">

    <h1>Title</h1>
    <div>
        ...
    </div>
</body>
</html>

window.onload

window.onload は、ブラウザウィンドウが完全に読み込まれた後に実行するイベントハンドラです。読み込み完了後の処理は、無名関数やアロー関数などで定義します。

window.onload = () => {
  // HTML読み込み後に処理
}

ローディング処理

HTMLにローディング用のタグを追加します。

dice2.html
<body>
  <!-- ローディング画面 -->
  <div id="loading" class="fixed inset-0 bg-white bg-opacity-90 flex justify-center items-center z-50">
    <div class="text-2xl font-semibold text-gray-700">Loading...</div>
  </div>

  ...
</body>

この状態でブラウザを確認すると、ローディングが表示されます。

ローディング非表示

window.onload HTML読み込み完了後にローディングを非表示にします。

js/dice2.js
// ウィンドウ読み込み完了後に実行
window.onload = () => {
    // ローディングを非表示
    const loadingElement = document.getElementById('loading');
    loadingElement.style.display = 'none';
}

動作確認

ブラウザを更新して、ローディングが非表示になるか確認します。

演習

問題1

タイマーを使って、キャラクター画像を動かしてみましょう。

ヒント

HTML を動かすためには、styleプロパティなどを変更し、位置を変更できます。

var character = document.getElementById('character');
character.style.position = 'absolute';
character.style.left = '10px';

問題2

キャラクター画像にマウスをあてたら、画像の位置を表示してみましょう。

ヒント

座標は getBoundingClientRect() などを利用すると取得できます。

var rect = character.getBoundingClientRect();

キャラクター「ぴぽや倉庫」