イベントの処理

JavaScriptプログラムでCSS特性を操作するということは、 マウスやキーボードでの対話的アクションをきっかけにすることが 多くなる。ユーザが起こしたマウスやキーボードの操作によって 計算機に伝わる事象のことをイベントという。ここでは、 イベント処理を行なうプログラム作成の指針を示す。

イベントリスナ

マウスクリックなど、イベントをきっかけに動くプログラムは、 処理起動対象としたいイベントについて、あらかじめその処理関数を 登録しておく必要がある。これをイベントリスナ(Event Listener)と いう。

例:

マウスクリック イベントリスナ

最も簡単な方法は、HTML要素の共通属性の onclick などに JavaScript の 関数呼出しを直接記述する方法であるが、HTMLの文書を追加するたびに いちいち onclick などをたさなければならず手間が倍増する。また、 HTML文書は「文書の内容を記述するもの」として 閉じているのが望ましいという観点からも、イベントリスナの登録は JavaScriptプログラムだけの力で行なうのがよい。

定義した関数をJavaScript自身でイベントリスナとするためには、 リスナ登録関数を利用する。リスナ登録関数を呼ぶ方法を知る前にJavaScript プログラムが呼ばれるタイミングについて考察する必要がある。

記述したJavaScriptが最初に読み込まれるのは、HTML文書内のscript要素で JavaScriptがロードされるときであるが、このときはHTML文書の読み込みが完了 していないので、イベントリスナ登録したい要素がまだ存在していない場合 がある。そのため、イベントリスナを一括登録する関数を定義しておき、 文書を全てロードし終わったときにその関数を呼ぶようにする。

簡単な例を以下に示す。

<ul>
 <li id="item-1">うじゃら</li>
 <li id="item-2">ほじゃら</li>
 <li id="item-3">でじゃら</li>
</ul>
function hello(ev) {
  alert(ev.target.id);
}
function addAll() {
  // lilistに全ての li 要素を得る
  var lilist = document.getElementsByTagName("li");
  for (var li of lilist) {
    // 最初から順にli要素をliに代入して繰り返す
    if (li.id && li.id.match(/^item-/)) {
      // そのli要素にid属性がありかつ /^item-/ にマッチするなら
      li.addEventListener("click", hello, false);
    }
  }
}
window.addEventListener("load", addAll, false);

上記の組み合わせの例では

という順番で、3つのli要素をクリックしたときのイベントリスナが 登録される。

特定の条件をもつ要素の探し方

イベントリスナの登録をするときに、たくさんの要素のうちから 特定の条件を持つ要素の全てを選び出す必要がある。その方法を 2つ紹介する。

同種の要素全ての中から探す

「HTML文書に含まれる同一要素全て」は document.getElementsByTagName() 関数で 全ての要素が詰まった配列を得ることができる。たとえば全ての p要素を得るなら

var allp = document.getElementsByTagName("p");
for (var item of allp) {
  if (itemがある条件を満たすか?) {
    item.addEventListener(イベント, 関数, false);
  }
}

のようにする。

特定の要素の子要素から探す

「id属性になんらかの値を持つ要素」は、 document.getElementById()関数で得られる。 その子要素全ての詰まった配列は childNodes で得られる。 たとえば、id属性に "foo" を持つ要素の子のうち、div要素全てを 選ぶ場合は以下のようにする。

var i;
var foo = document.getElementById("foo");
if (foo && foo.childNodes) {
  var c = foo.childNodes;
  for (i=0; i<c.length; i++) {
    if (c.tagName.match(/div/i)) {
      // 必要な処理
    }
  }
}

のようにする。

イベントリスナの作り方

イベントリスナとなる関数は、引数ひとつを取る形で定義する(※)。

function someListener(ev) {
  :
  :
}

※ 引数なしで宣言してもよい。

この関数が呼ばれるときに与えられる引数はイベントオブジェクト といい、それを介して発生したイベントの種類や位置(座標)を知ることができる。 上の例のように仮引数が ev だとした場合、イベントに関する 情報は以下の変数で取得できる。

意味
イベントが発生した要素 ev.target
スクリーン座標Xev.screenX
スクリーン座標Yev.screenY
ウィンドウ座標Xev.clientX
ウィンドウ座標Yev.clientY
イベントの種類ev.type
押したキーのコードev.keyCode

特定のclassを持つ要素すべてにイベントリスナを足す例

ここで、class="check" の属性設定を持つspan要素の すべてに「クリックされたら show() 完数を呼ぶ」処理を作成する例を示す。

まず、すべてのspan要素からclass属性を持つものを選別し、 イベントリスナを登録する処理は以下のようになる。

function show(ev) {
  var element = ev.target;
  element.style.backgroundColor = "yellow";
}
function addAll() {
  var item;
  var checks = document.getElementsByTagName("span"); //すべてのspan
  for (item of checks) {
    if (item.getAttribute("class") == "check") {
      item.addEventListener("click", show, false);	//show()関数を呼ぶ
    }
  }
}
window.onload = addAll;

show関数では、自分自身が呼ばれるきっかけとなった要素を検出し、 そのプロパティを変更している。

以上を利用して、前回の課題のチェックシートプログラムを作成したものを 示す。

checksheet.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
	"http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<title>Check Sheet</title>
<style type="text/css">
<!--
span.check {color: blue; background: blue;}
-->
</style>
<script type="text/javascript" src="checksheet.js"></script>
</head>

<body>
<h1>チェックシート</h1>
<p>CSSは<span class="check">Cascading Style Sheet</span>の略である。</p>
<p>HTMLは<span class="check">Hyper Text Mark-up Language</span>の略である。</p>
<p>Webの発明者は<span class="check">Tim Berners-Lee</span>である。</p>
</body>
</html>

checksheet.js

// background-color特性を yellow に変更する関数。
function show(ev) { // evには発生したイベント情報オブジェクトが代入される
  var element = ev.target;
  element.style.backgroundColor = "yellow";
}
// すべての <span class="check">...</span> にイベントリスナ
// として show() 関数を登録する
function addAll() {
  var item;
  var checks = document.getElementsByTagName("span"); //すべてのspan
  for (item of checks) {
    if (item.getAttribute("class") == "check") {
      item.addEventListener("click", show, false);	//show()関数を呼ぶ
    }
  }
}
//HTML文書ロード完了時に addAll() 関数が呼ばれるようにする。
window.onload = addAll;

実際の checksheet.html で動作確認せよ。

yuuji@koeki-u.ac.jp