Javascript-Ereignishandler mit Parametern


84

Ich möchte einen eventHandler erstellen, der das Ereignis und einige Parameter übergibt. Das Problem ist, dass die Funktion das Element nicht erhält. Hier ist ein Beispiel:

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
});

Das 'elem' muss außerhalb der anonymen Funktion definiert werden. Wie kann ich das übergebene Element in der anonymen Funktion verwenden? Gibt es eine Möglichkeit, dies zu tun?

Und was ist mit addEventListener? Ich scheine das Ereignis überhaupt nicht über einen addEventListener weiterleiten zu können, oder?

Aktualisieren

Ich schien das Problem mit "diesem" zu beheben.

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

Wo dies this.element enthält, auf das ich in der Funktion zugreifen kann.

Der addEventListener

Aber ich wundere mich über den addEventListener:

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

2
Sie haben Elemente, Elemente, Elemente in Ihrer Frage. Können Sie weniger verwirrend sein?
Mihai

Es tut mir leid, ich habe versucht, ein Beispiel für meine Situation zu machen, aber das lief nicht gut. Ich habe den Code aktualisiert.
sebas2day

Würden Sie suchen e.target/ e.currentTarget?
Rolf

1
Wie man einen Parameter sendet, wenn ich diesen verwende: ok.addEventListener ("click", this.changeText.bind (this));
Alberto Acuña

Antworten:


100

Ich verstehe nicht genau, was Ihr Code versucht, aber Sie können Variablen in jedem Event-Handler verfügbar machen, indem Sie die Vorteile von Funktionsabschlüssen nutzen:

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);
}

Abhängig von Ihrer genauen Codierungssituation können Sie so gut wie immer eine Art Schließung vornehmen, um den Zugriff auf die Variablen für Sie zu erhalten.

Aus Ihren Kommentaren geht Folgendes hervor:

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

Anschließend können Sie dies mit einer selbstausführenden Funktion (IIFE) tun, die die gewünschten Argumente in einem Abschluss erfasst, während sie ausgeführt wird, und die eigentliche Ereignishandlerfunktion zurückgibt:

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

Weitere Informationen zur Funktionsweise eines IIFE finden Sie in den folgenden Referenzen:

Javascript-Wrapping-Code in anonymer Funktion

Sofort aufgerufener Funktionsausdruck (IIFE) in JavaScript - Übergabe von jQuery

Was sind gute Anwendungsfälle für selbstausführende anonyme JavaScript-Funktionen?

Diese letzte Version ist vielleicht einfacher zu sehen, was es so macht:

// 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]));

Es ist auch möglich .bind(), einem Rückruf Argumente hinzuzufügen. Alle Argumente, an die Sie übergeben, .bind()werden den Argumenten vorangestellt, die der Rückruf selbst haben wird. Sie könnten dies also tun:

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));

Ja, das ist fast das, was ich versuche zu tun, aber was ist, wenn die anonyme Funktion vom addClickHandler als Parameter übergeben wird und Sie dieser Funktion einige Parameter mit dem Ereignis wie: element.addEventListener ('click', func (event, this.elements [i]));
sebas2day

5
@ sebas2day - Das kannst du nicht element.addEventListener('click', func(event, this.elements[i])). Javascript funktioniert einfach nicht so. Es gibt andere Möglichkeiten, Verschlüsse zu verwenden, aber Sie können es nicht so machen, wie Sie es geschrieben haben. addEventListener ruft seinen Rückruf mit genau einem Argument (dem Ereignis) auf, und Sie können dies in keiner Weise ändern.
jfriend00

Ich habe am Ende meiner Antwort ein weiteres Beispiel hinzugefügt.
jfriend00

@ jfriend00 Was Sie tun können, ist die Bindemethode zu verwenden. 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])) Beachten Sie, dass das Ereignisargument in den Argumenten für die Funktion immer das letzte ist und in der Bindemethode nicht explizit deklariert wird.
Ritter Yoshi

2
@ Bosh19 - Sehen Sie, was ich am Ende meiner Antwort hinzugefügt habe, um das Konstrukt zu erklären, nach dem Sie gefragt haben. Es handelt sich um einen sofort aufgerufenen Funktionsausdruck (IIFE), bei dem es sich im Wesentlichen um eine anonym deklarierte Funktion handelt, die sofort ausgeführt wird. Es ist eine Verknüpfung zum Definieren und anschließenden Aufrufen einer Funktion - nützlich, wenn Sie den Body inline haben möchten und er nirgendwo anders aufgerufen wird, sodass er keinen Namen benötigt.
jfriend00

28

Es ist eine alte, aber häufig gestellte Frage. Lassen Sie mich diesen hier hinzufügen.

Mit Pfeil Funktion Syntax können Sie ihm prägnante Art und Weise erreichen , da es lexikalisch binded und verkettet werden kann.

Ein Pfeilfunktionsausdruck ist eine syntaktisch kompakte Alternative zu einem regulären Funktionsausdruck, jedoch ohne eigene Bindung an die Schlüsselwörter this, arguments, super oder new.target.

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

Wenn Sie den Ereignis-Listener bereinigen müssen:

// 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);

Hier ist verrückter Einzeiler:

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

Fügsamere Version : Eher für jede vernünftige Arbeit geeignet.

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

2
Dies scheint eine vernünftige Lösung zu sein, aber was ist, wenn Sie denselben Ereignis-Listener entfernen müssen?
Dushyant Sabharwal

@SnnSnn: +1. Ich habe dies verwendet, um dem Ereignishandler eine Klasseneigenschaft bereitzustellen. Ich bin gerade vorbeigekommen thisund der Handler konnte auf das zugreifen, was er braucht.
Robotron

Wenn mein Verständnis korrekt ist, würden Sie tatsächlich eine anonyme Funktion als Ereignishandler übergeben: (e) => {....} und nicht yourEventHandlerFunction (). Dies führt zu Problemen, wenn Sie den Ereignishandler später entfernen möchten, da Sie zunächst eine anonyme Funktion übergeben haben.
PowerAktar vor

Die Antwort erklärt klar, wie man den Ereignis-Listener entfernt, also kein Problem.
snnsnn vor

9

Sie können versuchen, die Bindemethode zu verwenden. Ich denke, dies erreicht das, wonach Sie gefragt haben. Wenn nichts anderes, ist es immer noch sehr nützlich.

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

Angesichts der Aktualisierung der ursprünglichen Frage scheint es Probleme mit dem Kontext ("dies") beim Übergeben von Ereignishandlern zu geben. Die Grundlagen werden zB hier erklärt http://www.w3schools.com/js/js_function_invocation.asp

Eine einfache Arbeitsversion Ihres Beispiels könnte lauten

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);

Siehe auch Javascript call () & apply () vs bind ()?


2

Kurze Antwort:

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

... 

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

Das funktioniert nicht richtig. Wenn sich der Wert Ihrer Parameter bei jedem Festlegen des Ereignishandlers ändert, werden unerwartete Ergebnisse erzielt, da der Wert von param1oder nicht überschritten wird param2. Wenn sich diese Werte ändern, werden sie nicht auf den Wert gesetzt, der sie während der Erstellung des Ereignishandlers waren. Sie werden nur auf den aktuellen Wert gesetzt. Darüber hinaus unterscheidet sich dies nicht vom Festlegen einer Variablen außerhalb des Bereichs der Ereignis-Listener-Funktion und dem Verweisen auf diese Variable im Ereignishandler, sodass die Übergabe von Parametern überhaupt nicht möglich ist.
TetraDev

Ich habe Ihren Standpunkt nicht wirklich verstanden, daher könnte meine Antwort falsch sein. Wie auch immer, der Event-Handler wird einmal eingestellt (nicht immer, denke ich, aber normalerweise ist es das, was jemand will). Zweitens sagt dies ziemlich genau aus, dass die Handlerfunktion meine Funktion ist und dass sie 2 Parameter plus die Variable "event" hat. Drittens, ja, es funktioniert und die Ergebnisse sind genau wie erwartet.
user3093134

Nein es geht nicht. Ich habe es genau so getestet wie Sie und mein Punkt bleibt gültig. Wenn param1ist noodledas erste Mal , die addEventListener genannt wird, und das zweite Mal , wenn Sie es nennen, paramist cheesedann , wenn die Ereignis - Listener clickfeuert, param1wird festgelegt werden cheeseund nicht noodle. Daher wird kein "Abschluss" verwendet, um den Wert zu speichern, der zum Zeitpunkt des Hinzufügens des Ereignis-Listeners vorhanden war. Es gibt Szenarien, in denen der Ereignis-Listener mehrmals hinzugefügt werden muss, die nicht dargestellt werden müssen, damit mein Punkt gültig ist.
TetraDev

Ich bin kein Experte und habe noch nie von "Closure" in der Programmierung gehört, also verstehe ich nicht, was Sie damit meinen.
user3093134

1
Vielen Dank für das Auschecken. Ich werde auf jeden Fall auch die von Ihnen geposteten Links besuchen. Außerdem muss ich sagen, dass Sie sehr höflich und ehrlich sind, machen Sie weiter so und haben Sie einen guten Tag :)
user3093134

0

thisInnerhalb von doThingsbefindet sich das Fensterobjekt. Versuchen Sie stattdessen Folgendes:

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

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

    return {
        eventHandler: eventHandler
    };
};

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.