web-dev-qa-db-ja.com

addEventListenerは、無名関数で引数を渡すときに同じハンドルに対して複数回起動します

何らかの理由で、無名関数に引数を渡すときに、イベントリスナーが要素ごとに2回起動しています。つまり、要素elのクリックイベントは1回登録されるため、1回発生します。

el.addEventListener("click", handle, false);
el.addEventListener("click", handle, false);

しかし、私が自分の引数をそれに渡したい場合は、登録して2回起動します。

el.addEventListener("click", function() { handle(event, myArgument); }, false);
el.addEventListener("click", function() { handle(event, myArgument); }, false);

問題は、なぜ、そして何が解決策なのかということです。

私は他の場所を探しましたが、解決策を見つけられないか、この問題が発生している理由を理解できないようです。 addEventListenerで渡されたリスナー関数に引数を渡す方法 でソリューションを実装しようとしましたが、役に立ちませんでした-

基本的な無名関数またはクロージャを実行してから、以下に示すより高度なバージョンを実行しましたが、機能しました。

引数を渡さないと要素イベントが1回登録され、引数を渡すと要素イベントが2回登録される理由がわかりません。

コードは次のとおりです。

<html>
    <head>
        <script type="text/javascript">
            var handle_2 = function(evt, type) {
                var test;
                switch (type) {
                    case "focus": 
                        console.log(evt.target.value);
                        break;
                    case "click":
                        console.log(evt.target.id + " was clicked");
                        break;
                    default: console.log("no type found");
                }
            };

            window.onload = function() {
                var textbox = document.getElementById("t1");
                var button = document.getElementById("btn");
                textbox.value = "456";
                button.value = "Press";

                var typeFocus = "focus", typeClick = "click";

                textbox.addEventListener("focus", (function(typeFocus) { return function(evt) { handle_2(evt, typeFocus); }})(typeFocus), false);
                button.addEventListener("click", (function(typeClick) { return function(evt) { handle_2(evt, typeClick); }})(typeClick), false);

                // Registers again for each element. Why?
                textbox.addEventListener("focus", (function(typeFocus) { return function(evt) { handle_2(evt, typeFocus); }})(typeFocus), false);
                button.addEventListener("click", (function(typeClick) { return function(evt) { handle_2(evt, typeClick); }})(typeClick), false);
            };
        </script>
    </head>
    <body>
        <div id="wrapper">
            <input id="t1" type="text" />
            <input id="btn" type="button" />
        </div>
    </body>
</html>

どんな助けでもいただければ幸いです。ありがとうございました。

10
user717236

最も簡単な解決策は、新しいハンドラーを1回だけ作成することです。

var newHandle = function(event) { handle(event, myArgument); };

el.addEventListener("click", newHandle, false);
el.addEventListener("click", newHandle, false);
20
Felix Kling

上手、、

el.addEventListener("click", handle, false);
el.addEventListener("click", handle, false);

同じ関数「handle()」に登録します

el.addEventListener("click", function() { handle(event, myArgument); }, false);
el.addEventListener("click", function() { handle(event, myArgument); }, false);

2つの一意の無名関数である "function(){handle(event、myArgument)" ...を登録します。したがって、2回発砲します。

なぜ2回登録したいのか完全には理解していませんが、解決策は、パラメーターを受け取る関数を返す関数を作成することです。

el.addEventListener("click", crateHandle(myArgument), false);

var createHandle = function(myArgument) {
  return function(event) {
    .... do something
  };
}

それでも、2回の火災の問題は解決されません。

4
Stefan Svebeck

addEventListenerは、使用されている数のリスナーを登録します。

documentation によると、3つの引数を取り、3番目はuseCaptureであり、リスナーを2回登録するかどうかとは関係ありません。デフォルトではfalseに設定されているため、3番目のパラメーターとしてfalseを追加してもあまり変わりません。

0
strah