パラメータ付きのJavascriptイベントハンドラ


89

イベントといくつかのパラメーターを渡すeventHandlerを作成したいと思います。問題は、関数が要素を取得しないことです。次に例を示します。

doClick = function(func){
    var elem = .. // the element where it is all about
    elem.onclick = function(e){
        func(e, elem);
    }
}
doClick(function(e, element){
    // do stuff with element and the event
});

'elem'は無名関数の外部で定義する必要があります。渡された要素を匿名関数内で使用するにはどうすればよいですか?これを行う方法はありますか?

そして、addEventListenerはどうですか?addEventListenerを介してイベントを渡すことができないようです。

更新

'this'の問題を修正したようです

doClick = function(func){
    var that = this;
    this.element.onclick = function(e){
        func(e, that);
    }
}

これには、関数でアクセスできるthis.elementが含まれています。

addEventListener

しかし、私はaddEventListenerについて疑問に思っています:

function doClick(elem, func){
    element.addEventListener('click', func(event, elem), false);
}

2
あなたはあなたの質問に関係する要素、要素、要素を持っています。混乱を少なくすることはできますか?
mihai 2012

申し訳ありませんが、私は自分の状況の例を作ろうとしていましたが、これはうまくいきませんでした。コードを更新しました。
sebas2day 2012

e.target/をお探しe.currentTargetですか?
ロルフ

1
これを使用している場合にパラメータを送信する方法:ok.addEventListener( "click"、this.changeText.bind(this));
アルベルトアクーニャ2016

回答:


103

コードが何をしようとしているのか正確にはわかりませんが、関数クロージャの利点を使用して、任意のイベントハンドラーで変数を使用できるようにすることができます。

function addClickHandler(elem, arg1, arg2) {
    elem.addEventListener('click', function(e) {
        // in the event handler function here, you can directly refer
        // to arg1 and arg2 from the parent function arguments
    }, false);
}

正確なコーディング状況に応じて、ほとんどの場合、何らかのクロージャで変数へのアクセスを保持することができます。

あなたのコメントから、あなたが達成しようとしていることがこれであるならば:

element.addEventListener('click', func(event, this.elements[i]))

次に、実行時にクロージャに必要な引数をキャプチャして実際のイベントハンドラ関数を返す自己実行関数(IIFE)を使用してこれを行うことができます。

element.addEventListener('click', (function(passedInElement) {
    return function(e) {func(e, passedInElement); };
}) (this.elements[i]), false);

IIFEの仕組みの詳細については、以下の他の参考資料を参照してください。

匿名関数内のJavascriptラッピングコード

JavaScriptで即時呼び出し関数式(IIFE)-jQueryを渡す

JavaScriptが匿名関数を自己実行するための良いユースケースは何ですか?

この最後のバージョンは、おそらく次のように動作していることを確認するのが簡単です。

// return our event handler while capturing an argument in the closure
function handleEvent(passedInElement) {
    return function(e) {
        func(e, passedInElement); 
    };
}

element.addEventListener('click', handleEvent(this.elements[i]));

を使用.bind()して、コールバックに引数を追加することもできます。渡す引数はすべて.bind()、コールバック自体が持つ引数の前に追加されます。だから、あなたはこれを行うことができます:

elem.addEventListener('click', function(a1, a2, e) {
    // inside the event handler, you have access to both your arguments
    // and the event object that the event handler passes
}.bind(elem, arg1, arg2));

はい、これはほぼ私がやろうとしていることですが、匿名関数がaddClickHandlerによってパラメーターとして渡され、この関数に次のようなイベントでいくつかのパラメーターを指定したい場合はどうなりますか:element.addEventListener( 'click'、func(event、 this.elements [i]));
sebas2day 2012

5
@ sebas2day-できませんelement.addEventListener('click', func(event, this.elements[i]))。Javascriptはそのようには機能しません。クロージャを使用してそれを回避する他の方法がありますが、あなたが書いたようにそれを行うことはできません。addEventListenerは、1つの引数(イベント)を使用してコールバックを呼び出しますが、これを変更することはできません。
jfriend00 2012

私はこれを行う別の例を私の答えの最後に追加しました。
jfriend00 2012

@ jfriend00できることは、bindメソッドを使用することです。function eventFunction (arg, evt) { console.log(arg[0],arg[1],arg[2]) console.log(evt) } var el = document.getElementById('elementID'); el.addEventListener('click', eventFunction.bind(el,[1,2,3])) イベント引数は常に関数の引数の最後にあり、bindメソッドで明示的に宣言されていないことに注意してください。
ナイトヨッシー

2
@ Bosh19-あなたが尋ねた構成を説明するために、私の答えの最後に何を追加したかを見てください。これは即時呼び出し関数式(IIFE)であり、本質的には匿名で宣言された関数であり、すぐに実行されます。これは、関数を定義して呼び出すためのショートカットです。本文をインラインにしたい場合に便利です。他の場所では呼び出されないため、名前は必要ありません。
jfriend00 2015

28

これは古い質問ですが、よくある質問です。これをここに追加しましょう。

矢印関数の構文、それは辞書的にバインドされ、連鎖させることができますので、あなたはそれより簡潔な方法を達成することができます。

矢印関数式は、this、arguments、super、またはnew.targetキーワードへの独自のバインディングはありませんが、通常の関数式の構文的にコンパクトな代替手段です。

const event_handler = (event, arg) => console.log(event, arg);
el.addEventListener('click', (event) => event_handler(event, 'An argument'));

イベントリスナーをクリーンアップする必要がある場合:

// Let's use use good old function sytax
function event_handler(event, arg) {
  console.log(event, arg);
}

// Assign the listener callback to a variable
var doClick = (event) => event_handler(event, 'An argument'); 

el.addEventListener('click', doClick);

// Do some work...

// Then later in the code, clean up
el.removeEventListener('click', doClick);

これがクレイジーなワンライナーです:

// You can replace console.log with some other callback function
el.addEventListener('click', (event) => ((arg) => console.log(event, arg))('An argument'));

より従順なバージョン:あらゆる正気の仕事により適しています。

el.addEventListener('click', (event) => ((arg) => {
  console.log(event, arg);
})('An argument'));

2
これは合理的な解決策のように思えますが、同じイベントリスナーを削除する必要がある場合はどうでしょうか。
Dushyant Sabharwal 2018

@SnnSnn:+1。これを使用して、イベントハンドラーにクラスプロパティを提供しました。渡したところthis、ハンドラーは必要なものにアクセスできました。
ロボトロン

私の理解が正しければ、実際には匿名関数をイベントハンドラーとして渡すことになります:(e)=> {....}であり、yourEventHandlerFunction()ではありません。最初に無名関数を渡したので、後でイベントハンドラーを削除したい場合、これは問題を引き起こします???
PowerAktar

Answerは、イベントリスナーを削除する方法を明確に説明しているので、問題はありません。
snnsnn

9

あなたが試すことができる何かはbindメソッドを使うことです、私はこれがあなたが求めていたものを達成すると思います。他に何もないとしても、それはまだ非常に便利です。

function doClick(elem, func) {
  var diffElem = document.getElementById('some_element'); //could be the same or different element than the element in the doClick argument
  diffElem.addEventListener('click', func.bind(diffElem, elem))
}

function clickEvent(elem, evt) {
  console.log(this);
  console.log(elem); 
  // 'this' and elem can be the same thing if the first parameter 
  // of the bind method is the element the event is being attached to from the argument passed to doClick
  console.log(evt);
}

var elem = document.getElementById('elem_to_do_stuff_with');
doClick(elem, clickEvent);

2

元の質問が更新されたことを考えると、イベントハンドラーを渡すときにコンテキスト(「this」)に問題があるようです。基本はここで説明されています例えばここ http://www.w3schools.com/js/js_function_invocation.asp

あなたの例の簡単な作業バージョンは読むことができます

var doClick = function(event, additionalParameter){
    // do stuff with event and this being the triggering event and caller
}

element.addEventListener('click', function(event)
{
  var additionalParameter = ...;
  doClick.call(this, event, additionalParameter );
}, false);

Javascript call()&apply()vs bind()?も参照してください


2

短い答え:

x.addEventListener("click", function(e){myfunction(e, param1, param2)});

... 

function myfunction(e, param1, param1) {
    ... 
} 

これは正しく機能しません。イベントハンドラーが設定されるたびにパラメーターの値が変更されると、param1またはの値を超えないため、予期しない結果が生成されparam2ます。これらの値が変更された場合、イベントハンドラーが作成されたときの値には設定されません。現在の値のみに設定されます。さらに、これは、イベントリスナー関数のスコープ外に変数を設定し、イベントハンドラーでその変数を参照することと同じであるため、パラメーターの受け渡しはまったく行われません。
TetraDev

私は本当にあなたの主張を理解していなかったので、私の応答はずれているかもしれません。とにかく、イベントハンドラーは一度設定されます(いつも私が推測するわけではありませんが、通常それは誰かが望んでいることです)。次に、これは、ハンドラー関数がmyfunctionであり、2つのパラメーターと「event」変数があることを示しています。第三に、はい、それは機能し、結果は正確に期待どおりです。
user30931 3419年

いいえ、機能しません。私はあなたがしたのとまったく同じようにそれをテストしました、そして私のポイントは有効なままです。場合は param1あるnoodleのaddEventListenerが初めて呼び出されると、あなたは、それを呼び出す二回目は、paramあるcheeseイベントリスナーたび、その後click火災は、param1に設定されません。したがって、イベントリスナーが追加されたときに存在していた値を記憶するために「クロージャ」を使用しません。イベントリスナーを複数回追加する必要があるシナリオがありますが、私のポイントを有効にするために説明する必要はありません。cheesenoodle
TetraDev

私は専門家ではなく、プログラミングの「閉鎖」について聞いたことがないので、それが何を意味するのかわかりません。
user30931 3419年

1
ご覧いただきありがとうございます。投稿されたリンクにも必ずアクセスします。また、私はあなたが非常に礼儀正しく正直なサーであると言わなければなりません、それを維持し、良い一日を過ごしてください:)
user30931 3419年

0

this中にdoThingsはウィンドウオブジェクトがあります。代わりにこれを試してください:

var doThings = function (element) {
    var eventHandler = function(ev, func){
        if (element[ev] == undefined) {
            return;
        }

        element[ev] = function(e){
            func(e, element);
        }
    };

    return {
        eventHandler: eventHandler
    };
};

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.