web-dev-qa-db-ja.com

addEventListenerとonclick

addEventListeneronclickの違いは何ですか?

var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);

上記のコードは別々の.jsファイルにまとめられており、どちらも完全に機能します。

607
William Sham

どちらも正しいですが、どれもそれ自体が「最善」ではないため、開発者が両方のアプローチを使用することを選択した理由があるかもしれません。

イベントリスナー(addEventListenerおよびIEのattachEvent)

以前のバージョンのInternet Explorerでは、他のほとんどのブラウザとは異なる方法でJavaScriptが実装されています。 9より前のバージョンでは、次のようにattachEvent [ doc ]メソッドを使用します。

element.attachEvent('onclick', function() { /* do stuff here*/ });

他のほとんどのブラウザ(IE 9以降を含む)では、次のようにaddEventListener [ doc ]を使用します。

element.addEventListener('click', function() { /* do stuff here*/ }, false);

このアプローチ( DOM Level 2 events )を使用すると、理論上無制限の数のイベントを任意の単一の要素に添付できます。唯一の実際的な制限は、クライアントサイドのメモリとその他のパフォーマンスの問題です。これらはブラウザごとに異なります。

上記の例は無名関数[ doc ]の使用を表しています。関数参照[ doc ]またはクロージャー[ doc ]を使用してイベントリスナーを追加することもできます。

var myFunctionReference = function() { /* do stuff here*/ }

element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);

addEventListenerのもう1つの重要な機能はfinalパラメータです。これはリスナーがバブリングイベントにどう反応するかを制御します[ doc ]。例ではfalseを渡していますが、これはおそらくユースケースの95%に標準的なものです。 attachEventには、またはインラインイベントを使用する場合には、同等の引数はありません。

インラインイベント(HTML onclick = ""プロパティおよびelement.onclick)

JavaScriptをサポートするすべてのブラウザでは、イベントリスナをインラインで配置することができます。つまり、HTMLコード内で正しく処理できます。あなたはおそらくこれを見ました:

<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>

ほとんどの経験豊富な開発者はこの方法を避けていますが、それは仕事を成し遂げます。それは簡単で直接的です。ここでクロージャや無名関数を使用することはできません(ただし、ハンドラ自体はある種の無名関数です)が、スコープの制御は制限されています。

あなたが言及する他の方法:

element.onclick = function () { /*do stuff here */ };

...は、(HTMLではなくスクリプトを書いているので)スコープをより細かく制御でき、無名関数、関数参照、および/またはクロージャを使用できることを除いて、インラインJavaScriptと同じです。

インラインイベントの大きな欠点は、上記のイベントリスナーとは異なり、インラインイベントを1つだけ割り当てることができるということです。インラインイベントは、要素[ doc ]の属性/プロパティとして格納されます。つまり、上書きすることができます。

上記のHTMLの<a>の例を使用してください。

var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };

...要素をクリックすると、 only "Did stuff#2"を参照してください - 最初の代入onclickプロパティを2番目の値で上書きし、元のインラインHTMLのonclickプロパティを上書きしましたも。ここでそれをチェックしてください: http://jsfiddle.net/jpgah/

大まかに言って、 インラインイベントを使用しない 。特定のユースケースがあるかもしれませんが、そのユースケースが100%確信できない場合は、インラインイベントを使用しないでください。

現代のJavascript(Angularなど)

この答えが最初に投稿されて以来、AngularのようなJavaScriptフレームワークははるかに普及しています。 Angularテンプレートの中に次のようなコードがあります。

<button (click)="doSomething()">Do Something</button>

これはインラインイベントのように見えますが、違います。この種のテンプレートは、舞台裏でイベントリスナーを使用する、より複雑なコードに変換されます。ここで私がここでイベントについて書いたことはすべて当てはまりますが、あなたは少なくとも1つの層によって重要性から取り除かれます。基本を理解する必要がありますが、現代のJSフレームワークのベストプラクティスがこの種のコードをテンプレートに記述することを含む場合は、インラインイベントを使用しているとは思わないでください。

どれが一番いいの?

問題はブラウザの互換性と必要性​​の問題です。現在、要素に複数のイベントを添付する必要がありますか?あなたは将来的になりますか?オッズは、そうでしょう。 attachEventとaddEventListenerが必要です。そうでなければ、インラインイベントはトリックをするように思えるかもしれません、しかしそれはありそうにないかもしれませんが少なくとも予測可能である未来の準備のためにはるかに役立っています。 JSベースのイベントリスナーに移行しなければならない可能性があるので、そこから始めてください。インラインイベントを使用しないでください。

jQueryやその他のJavaScriptフレームワークは、DOMレベル2イベントのさまざまなブラウザ実装を一般的なモデルにカプセル化しているので、IEの歴史を反逆者として心配することなく、ブラウザに準拠したコードを書くことができます。 jQueryと同じコード、すべてクロスブラウザで、すぐに使える:

$(element).on('click', function () { /* do stuff */ });

ただし、この1つだけのために、実行してフレームワークを入手しないでください。あなたは簡単に古いブラウザの世話をするためにあなた自身の小さなユーティリティを転がすことができます:

function addEvent(element, evnt, funct){
  if (element.attachEvent)
   return element.attachEvent('on'+evnt, funct);
  else
   return element.addEventListener(evnt, funct, false);
}

// example
addEvent(
    document.getElementById('myElement'),
    'click',
    function () { alert('hi!'); }
);

それを試してみてください: http://jsfiddle.net/bmArj/ /

これらすべてを考慮に入れて、あなたが見ているスクリプトがブラウザの違いを他の方法で考慮しない限り(あなたの質問には示されていないコードで)、addEventListenerを使う部分はIEバージョンでは動作しません9未満.

ドキュメンテーションと関連読書

846
Chris Baker

この回答では、DOMイベントハンドラーを定義する3つの方法について説明します。

element.addEventListener()

コード例:

const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
<a href="//google.com">Try clicking this link.</a>

element.addEventListener()には複数の利点があります。

  • nlimitedイベントハンドラーを登録し、element.removeEventListener()で削除できます。
  • useCaptureパラメーターがあります。これは、キャプチャまたはバブリングフェーズでイベントを処理するかどうかを示します。参照: addEventListenerのuseCapture属性を理解できない
  • semanticsを気にします。基本的に、イベントハンドラーの登録をより明確にします。初心者にとって、関数呼び出しは何かが起こることを明らかにしますが、DOM要素のプロパティにイベントを割り当てることは少なくとも直感的ではありません。
  • 個別のドキュメント構造(HTML)とロジック(JavaScript)を許可します。小さなWebアプリケーションでは問題にならないように見えるかもしれませんが、どんな大きなプロジェクトでもは問題になります構造とロジックを分離するプロジェクトを維持するよりも、そうしないプロジェクトを維持する方がはるかに簡単です。
  • 正しいイベント名による混乱を排除します。インラインイベントリスナーを使用するか、DOM要素の.oneventプロパティにイベントリスナーを割り当てるため、多くの経験のないJavaScriptプログラマーは、イベント名が例えばonclickまたはonloadであると考えています。 onnotイベント名の一部です。正しいイベント名はclickおよびloadです。これが、イベント名が.addEventListener()に渡される方法です。
  • ほぼすべてのブラウザー で動作します。それでもIE <= 8をサポートする必要がある場合は、 MDNのポリフィル を使用できます。

element.onevent = function() {}(例:onclickonload

コード例:

const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
<a href="//google.com">Try clicking this link.</a>

これは、イベントハンドラーをDOM 0に登録する方法でした。以下の理由により、推奨されません。

  • 1つのみイベントハンドラーを登録できます。また、このメソッドを使用して割り当てられたイベントハンドラーを削除するには、oneventプロパティを初期状態(null)に戻す必要があるため、割り当てられたハンドラーの削除は直感的ではありません。
  • エラーに応答する適切ではありません。たとえば、誤ってwindow.onloadに文字列を割り当てた場合、たとえばwindow.onload = "test";はエラーをスローしません。あなたのコードは機能せず、その理由を見つけるのは本当に難しいでしょう。ただし、.addEventListener()はエラーをスローします(少なくともFirefoxでは):TypeError:EventTarget.addEventListenerの引数2はオブジェクトではありません
  • キャプチャ段階またはバブリング段階でイベントを処理するかどうかを選択する方法は提供されません。

インラインイベントハンドラー(onevent HTML属性)

コード例:

<a href="//google.com" onclick="event.preventDefault();">Try clicking this link.</a>

element.oneventと同様に、現在は推奨されていません。 element.oneventの問題に加えて、次のことを行います。

  • 潜在的なセキュリティの問題です。XSSがはるかに有害になるためです。現在、Webサイトは適切なContent-Security-Policy HTTPヘッダーを送信して、インラインスクリプトをブロックし、信頼できるドメインからの外部スクリプトのみを許可する必要があります。 コンテンツセキュリティポリシーの仕組み を参照してください
  • 個別のドキュメント構造とロジックではありません。
  • サーバー側スクリプトを使用してページを生成し、たとえばそれぞれが同じインラインイベントハンドラーを持つ100個のリンクを生成すると、イベントハンドラーが1回だけ定義された場合よりもコードがはるかに長くなります。つまり、クライアントはより多くのコンテンツをダウンロードする必要があり、その結果、Webサイトが遅くなります。

こちらもご覧ください

59

onclickはすべてのブラウザで機能しますが、addEventListenerは古いバージョンのInternet Explorerでは機能せず、代わりにattachEventを使用します。

onclickのマイナス面は、イベントハンドラは1つしか存在できず、他の2つは登録されたすべてのコールバックを起動するということです。

20
Magnar

私の知る限りでは、DOMの "load"イベントはまだ非常に限定的にしか機能しません。つまり、window objectimages<script>の各要素に対してのみ起動されます。直接onload代入についても同じことが言えます。両者に技術的な違いはありません。おそらく.onload =はより良いクロスブラウザの可用性を持っています。

ただし、load event<div>または<span>要素に割り当てることはできません。

12
jAndy

概要:

  1. addEventListenerでは複数のイベントを追加できますが、onclickではこれはできません。
  2. onclickHTML属性として追加できますが、addEventListener<script>要素内にのみ追加できます。
  3. addEventListenerは、イベント伝播を停止させることができる3番目の引数を取ることができます。

どちらもイベントの処理に使用できます。ただし、addEventListenerは、onclickが実行できることすべてを実行できることから、推奨される選択肢です。 JavaScriptとHTMLが混同されるため、HTML属性としてインラインonclickを使用しないでください。コードが保守しにくくなります。

4

_ mdn _ によると、違いは以下のとおりです。

addEventListener:

EventTarget.addEventListener()メソッドは、呼び出されたEventTarget上の指定されたイベントタイプのイベントリスナーのリストに、指定されたEventListener互換オブジェクトを追加します。イベントターゲットは、ドキュメント内の要素、ドキュメント自体、ウィンドウ、またはイベントをサポートするその他のオブジェクト(XMLHttpRequestなど)です。

onclick:

Onclickプロパティは、現在の要素のクリックイベントハンドラコードを返します。 clickイベントを使用してアクションをトリガーするときは、マウスまたはタッチスクリーンを使用していない人が同じアクションを使用できるように、これと同じアクションをkeydownイベントに追加することも検討してください。構文element.onclick = functionRef; functionRefは関数です。他の場所で宣言された関数の名前または関数式です。詳細は、 "JavaScriptガイド:関数"を参照してください。

以下のコードに見られるように、使用には構文上の違いもあります。

addEventListener:

// Function to change the content of t2
function modifyText() {
  var t2 = document.getElementById("t2");
  if (t2.firstChild.nodeValue == "three") {
    t2.firstChild.nodeValue = "two";
  } else {
    t2.firstChild.nodeValue = "three";
  }
}

// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);

onclick:

function initElement() {
    var p = document.getElementById("foo");
    // NOTE: showAlert(); or showAlert(param); will NOT work here.
    // Must be a reference to a function name, not a function call.
    p.onclick = showAlert;
};

function showAlert(event) {
    alert("onclick Event detected!");
}
2
Alireza

ブラウザのサポートについてあまり心配していないのであれば、イベントによって呼び出された関数内で 'this'参照を再バインドする方法があります。通常は、関数が実行されたときにイベントを生成した要素を指しますが、これは必ずしも必要なものではありません。注意が必要なのは、この例に示すように、まったく同じイベントリスナーを同時に削除できるようにすることです。 http://jsfiddle.net/roenbaeck/vBYu3/

/*
    Testing that the function returned from bind is rereferenceable, 
    such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
    // the following is necessary as calling bind again does 
    // not return the same function, so instead we replace the 
    // original function with the one bound to this instance
    this.swap = this.swap.bind(this); 
    this.element = document.createElement('div');
    this.element.addEventListener('click', this.swap, false);
    document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
    element: null,
    swap: function() {
        // now this function can be properly removed 
        this.element.removeEventListener('click', this.swap, false);           
    }
}

上記のコードはChromeでもうまく機能します。おそらく他のブラウザと「バインド」互換性を持たせるためのシムがいくつかあります。

1
Lars Rönnbäck

詳細についてはまだ触れていません。最近のデスクトップブラウザでは、デフォルトでAddEventListener('click'onclickのボタンクリックが異なると見なされています。

  • Chrome 42とIE11では、onclickAddEventListenerの両方のクリックが左クリックと中クリックで起動します。
  • Firefox 38では、onclickは左クリックで only を起動しますが、AddEventListenerクリックは左、中右クリックで起動します。

また、スクロールカーソルが関係している場合、中クリックの振る舞いはブラウザ間で 非常に 矛盾します。

  • Firefoxでは、中クリックイベントは常に発生します。
  • Chromeでは、中央のクリックでスクロールカーソルが開いても閉じても起動しません。
  • IEでは、スクロールカーソルが閉じると起動しますが、開くと起動しません。

また、inputのようなキーボードで選択可能なHTML要素の「クリック」イベントもスペースで発生するか、または要素が選択されたときに入力されることにも注目に値します。

1
a guest

それをプロトタイプ化することによってリスナーを拡張することも可能です(私たちがそれを参照していて、それが無名関数ではない場合) - または 'onclick'が関数ライブラリへの呼び出しを呼び出すようにする(他の関数を呼び出す関数)

好き

    Elm.onclick = myFunctionList
    function myFunctionList(){
      myFunc1();
      myFunc2();
    }

これは、onclick呼び出しを変更して関数myFunctionList()を変更して、必要な処理を実行する必要がないことを意味しますが、これはバブリング/キャッチ段階の制御なしに行われるため、新しいブラウザでは避けてください。

念のために、誰かが将来このスレッドを見つけたら...

1
patrik

インラインハンドラの使用は コンテンツセキュリティポリシーとの互換性がありません そのためaddEventListenerアプローチはその観点からより安全です。もちろん、インラインハンドラをunsafe-inlineで有効にすることもできますが、その名前が示すように、CSPが防止するJavaScriptの悪用の大部分を取り戻すので安全ではありません。

1
kravietz

JavasSriptの'this'キーワードで参照されるコンテキストは異なります。

次のコードを見てください:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>

</head>
<body>
    <input id="btnSubmit" type="button" value="Submit" />
    <script>
        function disable() {
            this.disabled = true;
        }
        var btnSubmit = document.getElementById('btnSubmit');
        btnSubmit.onclick = disable();
        //btnSubmit.addEventListener('click', disable, false);
    </script>
</body>
</html>

それがすることは本当に簡単です。ボタンをクリックすると、ボタンは自動的に無効になります。

最初にこの方法でイベントをフックしようとすると、ボタンをクリックするとbutton.onclick = function(), onclickイベントがトリガーされますが、button.onclickイベントハンドラーとonclickイベントハンドラーの間には明示的なバインドがないため、ボタンは無効になりません。 'this'オブジェクトをデバッグすると、'window'オブジェクトを参照していることがわかります。

第二に、btnSubmit.onclick = disable();をコメントして//btnSubmit.addEventListener('click', disable, false);のコメントを解除すると、button.onclickイベントとonclickイベントハンドラーの間に明示的なバインディングがあるため、ボタンが無効になっていることがわかります。無効化機能にデバッグすると、'this'windowではなくbutton controlを参照していることがわかります。

これは、一貫性のないJavaScriptについて私が嫌いなものです。ところで、jQuery($('#btnSubmit').on('click', disable);)を使用している場合、明示的なバインディングを使用します。

0
Larry

Javascriptはすべてをオブジェクトに融合する傾向があり、混乱を招く可能性があります。 1つにすべてJavaScriptの方法です。

基本的にonclickはHTMLの属性です。逆にaddEventListenerは、HTML要素を表すDOMオブジェクト上のメソッドです。

JavaScriptオブジェクトでは、メソッドは値として関数を持ち、それが関連付けられているオブジェクトに対して機能する単なるプロパティです(これを使用してなど)。

DOMでは、HTML要素としてのJavaScriptでは、その属性がそのプロパティにマッピングされます。

JavaScriptが間接層なしで単一のコンテナまたは名前空間にすべてを融合するので、これは人々が混乱するところです。

通常のOOレイアウト(これは少なくともプロパティ/メソッドの名前空間をマージします)では、次のようになるでしょう。

domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))

Onloadにはgetter/setterを、属性にはHashMapを使うことができるようなバリエーションがありますが、最終的にはそのようになります。 JavaScriptは、何が他のものの中にあるのかを知ることを期待して、その間接層を排除しました。それはdomElementと属性をまとめました。

互換性を排除するために、ベストプラクティスとしてaddEventListenerを使用してください。他の回答として、基本的なプログラム上の違いではなく、その点での違いについて説明します。基本的に、理想的な世界ではHTMLからon *を使用することだけを意図していますが、さらに理想的な世界ではHTMLからそのようなことをしてはいけません。

今日はなぜそれが支配的なのですか?それは書くのが速く、学ぶのがより簡単で、ちょうど働く傾向があります。

HTMLでのonloadの全体的なポイントは、まずaddEventListenerメソッドまたは機能へのアクセスを許可することです。あなたが直接それを適用することができたときにJSでそれを使用することによってあなたはHTMLを経験しています。

仮説的にあなたはあなた自身の属性を作ることができます:

$('[myclick]').each(function(i, v) {
     v.addEventListener('click', function() {
         eval(v.myclick); // eval($(v).attr('myclick'));
     });
});

JSがすることはそれとは少し異なります。

あなたはそれを(作成されたすべての要素に対して)のようなものとみなすことができます。

element.addEventListener('click', function() {
    switch(typeof element.onclick) {
          case 'string':eval(element.onclick);break;
          case 'function':element.onclick();break;
     }
});

実際の実装の詳細は、微妙なバリエーションの範囲によって異なる可能性がありますが、場合によっては両者の違いがわずかに異なりますが、それがその要旨です。

デフォルトでは属性はすべて文字列なので、関数をon属性に固定できることは、おそらく互換性のためのハックです。

0
jgmjgm

addEventListenerを使用すると、複数のハンドラを設定できますが、IE 8以下ではサポートされません。

IEにはattachEventがありますが、まったく同じではありません。

0
user113716