読者です 読者をやめる 読者になる 読者になる

Webデザインの勉強 ハロートレーニング 受講生のためのWebデザインの勉強補足ブログ

イベントハンドラの設定

イベント

  • 何かが行われたときの処理を予約する


《例》

  • ボタンをクリックしたときにアラートを出す
  • マウスオーバーしたときに画像を切り替える
  • キーボードのキーが押されたときに入力候補を表示する
  • フォームの値を変更したときに入力値をチェックする
  • ウィンドウの幅が変わったときにCSSを切り替える

など

HTMLとJavaScriptの分離

  • いままでの記述では、イベントハンドラはHTML内に記述していました
  • 定義とイベントが発生する位置がばらばらでわかりにくくなっています
  • Webページを作成する際は、HTMLとスクリプトは分けて記述することが推奨されています
イベントハンドラの変更



 要素.イベントハンドラ = 定義済みの関数名;


または



 要素.イベントハンドラ = function 関数名() { };

スクリプトによるイベントハンドラ
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>JavaScriptの練習</title>
<script>
  function showImage() {
    var htmlstr = "";
    for(var i=1; i<=3; i++) {
      htmlstr += "<img src='img/sweets" + i + ".jpg'>";
    }
    document.getElementById( 'imageArea' ).innerHTML = htmlstr;
  }
  
  document.getElementById( 'btn' ).onclick = showImage;
</script>
</head>
<body>
<button id="btn">読込</button>
<div id="imageArea">ここに画像が読み込まれます。</div>
</body>
</html>



実行するとコンソールにエラーメッセージが表示されます。


イベントハンドラが実行される過程

  1. HTMLタグは、基本的に上から順に解釈されます
  2. そして scriptタグ内の処理を実行しているときは、以降のタグの読み込みはストップしています
  3. つまり、追加した行の段階では、まだ「btn」というID値をもつ要素が読み込まれていない状態です
  4. その状態で、getElementByIdメソッドを実行すると、要素が見つからないため、戻り値は null(オブジェクトが無いことを表す値)になります
  5. nullに対してonclickイベントハンドラを設定することはできないので、エラーが発生していました


いままでの記述のように、bodyの終了タグの上に scriptを移動してくると解決します。
現在では、scriptの記述する位置がその位置に設定されているのも、そういう理由からです。


しかし、分離という目的からはずれています。

引数のある関数をイベントハンドラに設定する
  • イベントらハンドラに対して関数式で匿名関数を代入し、匿名関数の中で引数をつけて呼び出します
  • 引数が必要な関数は、匿名関数で包みます


《引数が無い場合》

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>JavaScriptの練習</title>
<script>
  function showImage() {
    var htmlstr = "";
    for(var i=1; i<=3; i++) {
      htmlstr += "<img src='img/sweets" + i + ".jpg'>";
    }
    document.getElementById( 'imageArea' ).innerHTML = htmlstr;
    this.disabled = true;
  }
  window.onload = function() {
    document.getElementById( 'btn' ).onclick = showImage;
  };
</script>
</head>
<body>
<button id="btn">読込</button>
<div id="imageArea">ここに画像が読み込まれます。</div>
</body>
</html>


《引数がある場合》

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>JavaScriptの練習</title>
<script>
  function showImage(number) {
    var htmlstr = "<img src='img/sweets" + number + ".jpg'>";
    document.getElementById( 'imageArea' ).innerHTML = htmlstr;
  }
  window.onload = function() {
    document.getElementById( 'btn' ).onclick = function() {
      showImage(1);
    };
  };
</script>
</head>
<body>
<button id="btn">読込</button>
<div id="imageArea">ここに画像が読み込まれます。</div>
</body>
</html>
  • この場合、1番目の画像ののみが表示されます

要素のプロパティによるイベントの設定


対象の要素 . 何か起きたら = 何かする ;

何かするところに関数を使う
  • 無名関数(名前付けされずに定義された関数)
  • 関数は随時実行するわけではなく、ページが読み終わった段階で実行する役割があります(HTMLの内容がブラウザに表示された後に実行されます)
<button id="btn">ボタン</button>
<script>
window.onload = function() {
  // btn要素を取得
  var btn = document.getElementById( 'btn' );

  // btnにクリックイベントを設定
  btn.onclick = function() {
      // クリックされたらアラートを出す
      alert('clicked');
  };
};
</script>
要素のプロパティによるイベント設定の欠点
  • 1つの要素に同じ種類のイベントは1つしか設定できません
<div id="box">This is box</div>
<button id="btn">ボタン</button>
<script>
window.onload = function() {
  // 要素を取得
  var btn = document.getElementById( 'btn' );
  var box = document.getElementById( 'box' );

  // 背景色を赤くするイベント
  btn.onclick = function() {
    box.style.backgroundColor = 'yellowgreen';
  };

  // アラートを表示するイベント
  btn.onclick = function() {
    alert('clicked');
  };
};
</script>

1つ目のイベントは上書きされて無効になります。

addEventListenerによるイベントの設定

  • 同じ要素に同じ種類のイベントをいくつでも設定できる関数です


対象の要素 . addEventListener ( 何か起きたら, 何かする, false ) ;

<div id="box">This is box</div>
<button id="btn">ボタン</button>
<script>
window.onload = function() {
  // 要素を取得
  var btn = document.getElementById( 'btn' );
  var box = document.getElementById( 'box' );

  // 背景色を赤くするイベント
  btn.addEventListener('click', function() {
      box.style.backgroundColor = 'yellowgreen';
  }, false);

  // アラートを表示するイベント
  btn.addEventListener( 'click', function() {
      alert('clicked');
  }, false );
};
</script>
  • addEventListenerは、複数イベントを設定しても前のイベントを上書きしません
addEventListenerによるイベント設定の欠点
  • addEventListenerは、イベントは複数設定できる利点があるので積極的に使っていきたいのですが、IE8以下では対応していません
  • IE8以下では attachEventという関数を使うことになりますが、プログラムが複雑になってしまう欠点があります
  • jQueryを使えば、これらの良いところを合わせたイベント処理ができます

window.onload と DOMContentLoaded

<script>
// id名がboxの要素を取得
var box = document.getElementById('box');
// 要素を取得できていないことが確認できる
console.log(box); //=> null
</script>
<div id="box">This is box</div>
  • getElementById が null になるのは、指定した id名の要素が見つからなかった場合です
  • script要素が実行されてから、div要素を読みにいきます(id名boxが見つからない)
  • script要素がとdiv要素を反対にすれば、処理が実行されます
  • 現在、script要素をbodyの終了タグ前に記述する理由でもあります
window.onload - 「HTMLの読み込みが終わったら」というイベント
  • window.onload を使うことで、どこにscript要素をおいても要素を取得できるようになります
  • 欠点は、画像ファイルなどの外部ファイルのダウンロードもすべて終了しないとイベントの処理が実行されないことです
<div id="box">This is box</div>
<script>
// 「HTMLの読み込みが終わったら」というイベントを設定
window.onload = function() {
  // id名がboxの要素を取得
  var box = document.getElementById('box');

  // 要素が取得できていることが確認できる
  console.log(box); //=> <div id="box">This is box</div>
};
</script>
DOMContentLoaded - 「HTMLを取得・操作可能な準備ができたら」というイベント
  • window.onload と同じく、HTMLの読み込みが終わった時点で処理が実行されるイベントです
  • 画像のダウンロードなどを待たずに、HTMLをJavaScriptから取得・操作可能な準備ができた時点で実行されるので、window.onload より早く処理されます
  • しかし DOMContentLoaded イベントは、要素のプロパティにイベントを設定する方法では設定できないので、addEventListener で設定する必要があります
<div id="box">This is box</div>
<script>
// 「HTMLの読み込みが終わったら」というイベントを設定
document.addEventListener('DOMContentLoaded', function() {
  // id名がboxの要素を取得
  var box = document.getElementById('box');

  // 要素が取得できていることが確認できる
  console.log(box); //=> HTMLDivElement
}, false);
</script>
  • IE8以下では対応しません
  • jQueryにはこの処理を簡単に行える「$(function() { })」という機能があります


ここまでの内容の理解が、jQueryを理解するためには必須です。