DOM onevent ハンドラー

ウェブプラットフォームでは、DOM イベントの通知を受け取るための方法をいくつか提供しています。よく使われる方法は2つあり、 addEventListener() と、特定の onevent ハンドラーです。このページでは、後者がどのように機能するのかについて注目します。

onevent ハンドラーの登録

onevent ハンドラーは特定の DOM 要素のプロパティで、その要素がイベントに対してどのように反応するかを管理します。要素には、対話的なもの (リンク、ボタン、画像、フォームなど) と対話的ではないもの (基本の <body> 要素など) があります。イベントとは、以下のようなアクションのことです。

  • クリックされた
  • キーの押下が検出された
  • フォーカスを受け取った

onevent ハンドラーは通常、onclick, onkeypress, onfocus など、反応するイベントに従って名前が付けられています。

on<…> イベントハンドラーを指定することで、指定されたオブジェクトの特定のイベント (click など) に対してさまざまな方法で指定することができます。

  • 要素に on<eventtype> という名前の HTML 属性を追加する方法。
    <button onclick="handleClick()">,
  • または、JavaScript から対応する property を設定する方法。
    document.querySelector("button").onclick = function(event) { … }.

onevent イベントハンドラープロパティは、1 つのイベントハンドラーを割り当てることができる一種のプレースホルダーとして機能します。与えられたオブジェクト上の同じイベントに対して複数のハンドラーをインストールできるようにするには、その addEventListener() メソッドを呼び出して、オブジェクト上の与えられたイベントに対するハンドラーのリストを管理することができます。ハンドラーは、その removeEventListener() 関数を呼び出すことで、オブジェクトから削除することができます。

要素に適用されるイベントが発生すると、そのイベントハンドラーが次々と呼び出され、イベントを処理できるようになります。自分で呼び出す必要はありませんが、多くの場合、イベントの発生を簡単にシミュレートするために呼び出すことができます。例えば、ボタンオブジェクト myButton を指定した場合、 myButton.onclick(myEventObject) を実行することでイベントハンドラーを直接呼び出すことができます。イベントハンドラーがイベントオブジェクトからデータにアクセスしない場合は、 onclick() を呼び出すときにイベントを省略することができます。

これは、イベントハンドラーのいずれかがイベントオブジェクト自身に対して stopPropagation() を呼び出すことでイベントの処理を明示的に停止しない限り、すべてのハンドラーが呼び出されるまで続きます。

要素以外のオブジェクト

イベントハンドラーはまた、 window, document, XMLHttpRequest などを含む、イベントを生成する多くの要素以外のオブジェクトのプロパティを使用して設定することもできます。例えば、 progress イベントが XMLHttpRequest のインスタンスで発生した場合は次のようになります。

const xhr = new XMLHttpRequest();
xhr.onprogress = function() { … };

HTML の onevent 属性

HTML 要素には onevent という名前の属性があり、これを利用して HTML コード内に直接イベントのハンドラーを登録することができます。要素が HTML から構築されると、その onevent 属性の値がその要素を表す DOM オブジェクトにコピーされるので、JavaScript を使って属性の値にアクセスすると、HTML で設定された値が得られます。

HTML の属性値への更なる変更は setAttribute メソッドで行うことができます。 JavaScript プロパティを変更しても効果あありません。

HTML

このような HTML 文書があったとします。

<p>Demonstrating quirks of <code>on<em>event</em></code> HTML attributes on
   <a onclick="log('Click!')">these three words</a>.
</p>

<div></div>

JavaScript

この JavaScript は、 HTML 属性の値が JavaScript オブジェクトのプロパティの変更によって影響を受けないことを示しています。

let logElement = document.querySelector('div');
let el = document.querySelector("a");

function log(msg) { logElement.innerHTML += `${msg}<br>` };
function anchorOnClick(event) { log("Changed onclick handler") };

// Original Handler
log(`Element's onclick as a JavaScript property: <code> ${el.onclick.toString()} </code>`);

//Changing handler using .onclick
log('<br>Changing onclick handler using <strong> onclick property </strong> ');

el.onclick = anchorOnClick;

log(`Changed the property to: <code> ${el.onclick.toString()} </code>`);
log(`But the HTML attribute is unchanged: <code> ${el.getAttribute("onclick")} </code><br>`);

//Changing handler using .setAttribute
log('<hr/><br> Changing onclick handler using <strong> setAttribute method </strong> ');
el.setAttribute("onclick", 'anchorOnClick(event)');

log(`Changed the property to: <code> ${el.onclick.toString()} </code>`);
log(`Now even the HTML attribute has changed: <code> ${el.getAttribute("onclick")} </code><br>`);

結果

歴史的な理由から、<body> および <frameset> 要素の一部の属性/プロパティは、実際にはその親 Window オブジェクトにイベントハンドラーを設定します。(HTML 仕様はこれらを onblur, onerror, onfocus, onload, onscroll と命名しています。)

イベントハンドラーの引数、this の結びつけ、および返値

イベントハンドラーが HTML 属性として指定されている場合、指定されたコードは次の引数を持つ関数にラップされます。

  • event - {domxref("GlobalEventHandlers.onerror", "onerror")}} を除くすべてのイベントハンドラー。
  • event, source, lineno, colno, error - onerror のイベントハンドラー。なお、 event 引数には、実際にはエラーメッセージが文字列として含まれています。

イベントハンドラーが呼び出されると、ハンドラー内の this キーワードは、ハンドラーが登録されている DOM 要素に設定されます。詳しくは、this キーワードのドキュメントを参照してください。

ハンドラーからの返値は、イベントが取り消されるかどうかを決定します。返値値の具体的な処理はイベントの種類によって異なります。詳細については、HTML 仕様の「イベントハンドラー処理アルゴリズム」を参照してください。

イベントハンドラーが呼び出されたとき

作成中 (非捕獲リスナー)

用語集

イベントハンドラーという用語は、次のように使用されます。

  • イベントの通知を受けるように登録されている関数またはオブジェクト
  • または、より具体的には、<button onclick="alert(this)">window.onload = function() { … }など、HTML の on… 属性または Web API のプロパティを介してイベントリスナーを登録するメカニズム。

イベントを待ち受けするためのさまざまな方法を議論するときは、

  • イベントリスナーは、EventTarget.addEventListener() によって登録された関数またはオブジェクトを参照します。
  • 一方、イベントハンドラーon... 属性またはプロパティを介して登録された関数を指します。

仕様書

仕様書 状態 備考
HTML Living Standard
event handlers の定義
現行の標準
HTML5
event handlers の定義
勧告

ブラウザーの互換性

イベントハンドラープロパティが存在することの検出

JavaScript の in 演算子でイベントハンドラープロパティの存在を検出することができます。例えば、以下のようになります。

if ("onsomenewfeature" in window) {
  /* do something amazing */
}

イベントハンドラーとプロトタイプ

DOM プロトタイプオブジェクトには、IDL で定義された属性の値を設定したり、アクセスしたりすることはできません。つまり、例えば Window.prototype.onload を変更することはできません。以前は、 Gecko では イベントハンドラー (onload など) が IDL 属性として実装されていなかったので可能だったのですが、現在はできなくなりました。これにより互換性が向上します。