Gestore di eventi Javascript con parametri


92

Voglio creare un eventHandler che passi l'evento e alcuni parametri. Il problema è che la funzione non ottiene l'elemento. Ecco un esempio:

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

L '"elemento" deve essere definito al di fuori della funzione anonima. Come posso ottenere l'elemento passato da utilizzare all'interno della funzione anonima? C'è un modo per fare questo?

E per quanto riguarda addEventListener? Non mi sembra di essere in grado di passare l'evento tramite un addEventListener, vero?

Aggiornare

Mi sembrava di risolvere il problema con "questo"

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

Dove questo contiene questo elemento a cui posso accedere nella funzione.

Il addEventListener

Ma mi chiedo di addEventListener:

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

2
Hai elementi, elementi, elementi coinvolti nella tua domanda. Puoi essere meno confuso?
mihai

Mi dispiace, stavo cercando di fare un esempio della mia situazione ma non è andata bene, ho aggiornato il codice.
sabato

Cerchi e.target/ e.currentTarget?
Rolf

1
come inviare un parametro se sto usando questo: ok.addEventListener ("click", this.changeText.bind (this));
Alberto Acuña

Risposte:


103

Non capisco esattamente cosa stia cercando di fare il tuo codice, ma puoi rendere le variabili disponibili in qualsiasi gestore di eventi utilizzando i vantaggi delle chiusure di funzioni:

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

A seconda della tua esatta situazione di codifica, puoi praticamente sempre fare una sorta di chiusura per preservare l'accesso alle variabili per te.

Dai tuoi commenti, se quello che stai cercando di ottenere è questo:

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

Quindi, potresti farlo con una funzione autoeseguente (IIFE) che acquisisce gli argomenti desiderati in una chiusura mentre esegue e restituisce la funzione di gestore di eventi effettiva:

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

Per ulteriori informazioni su come funziona un IIFE, vedere questi altri riferimenti:

Codice di wrapping Javascript all'interno di una funzione anonima

Espressione di funzione immediatamente invocata (IIFE) in JavaScript - Passaggio di jQuery

Quali sono i buoni casi d'uso per JavaScript che esegue automaticamente funzioni anonime?

Quest'ultima versione è forse più facile da vedere cosa sta facendo in questo modo:

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

È anche possibile utilizzare .bind()per aggiungere argomenti a un callback. Qualsiasi argomento a cui si passa .bind()verrà anteposto agli argomenti che avrà il callback stesso. Quindi, potresti fare questo:

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

sì, è quasi quello che sto cercando di fare, ma cosa succede se la funzione anonima viene passata come parametro da addClickHandler e vuoi dare a questa funzione alcuni parametri con l'evento come: element.addEventListener ('click', func (event, this.elements [i]));
sabato

5
@ sebas2day - Non puoi farlo element.addEventListener('click', func(event, this.elements[i])). Javascript non funziona in questo modo. Ci sono altri modi per aggirare questo, usando le chiusure, ma non puoi farlo nel modo in cui hai scritto. addEventListener chiama il suo callback con esattamente un argomento (l'evento) e non puoi cambiarlo in alcun modo.
jfriend00

Ho aggiunto un altro esempio di questa operazione alla fine della mia risposta.
jfriend00

@ jfriend00 Quello che potresti fare è usare il metodo 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])) Notare che l'argomento dell'evento è sempre l'ultimo negli argomenti della funzione e non è dichiarato esplicitamente nel metodo bind.
Knight Yoshi

2
@ Bosh19 - guarda cosa ho aggiunto alla fine della mia risposta per spiegare il costrutto che hai chiesto. È un'espressione di funzione immediatamente invocata (IIFE) che è essenzialmente una funzione dichiarata in modo anonimo che viene eseguita immediatamente. È una scorciatoia per definire una funzione e quindi chiamarla: utile quando si desidera che il corpo sia in linea e non verrà chiamato da nessun'altra parte, quindi non ha bisogno di un nome.
jfriend00

29

È una domanda vecchia ma comune. Quindi lasciatemi aggiungere questo qui.

Con la sintassi della funzione freccia puoi ottenerla in modo più succinto poiché è legata lessicalmente e può essere concatenata.

Un'espressione di funzione freccia è un'alternativa sintatticamente compatta a un'espressione di funzione regolare, sebbene priva di vincoli propri alle parole chiave this, arguments, super o new.target.

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

Se è necessario pulire il listener di eventi:

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

Ecco una battuta folle:

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

Versione più docile : più appropriata per qualsiasi lavoro sano.

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

2
Questa sembra una soluzione ragionevole, ma cosa succede quando devi rimuovere lo stesso listener di eventi?
Dushyant Sabharwal

@SnnSnn: +1. L'ho usato per fornire una proprietà di classe al gestore di eventi. Sono appena passato thise l'handler ha potuto accedere a ciò di cui ha bisogno.
Robotron

1
Se la mia comprensione è corretta, in realtà passeresti una funzione anonima come gestore di eventi: (e) => {....} e non yourEventHandlerFunction (). Ciò causerà problemi se desideri rimuovere il gestore di eventi in un secondo momento, poiché hai passato una funzione anonima per iniziare con ???
PowerAktar

La risposta spiega chiaramente come rimuovere il listener di eventi, quindi nessun problema.
snnsnn

9

Qualcosa che puoi provare sta usando il metodo bind, penso che questo ottenga ciò che stavi chiedendo. Se non altro, è comunque molto utile.

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

Dato l'aggiornamento alla domanda originale, sembra che ci siano problemi con il contesto ("questo") durante il passaggio dei gestori di eventi. Le basi sono spiegate ad esempio qui http://www.w3schools.com/js/js_function_invocation.asp

Potrebbe leggere una semplice versione funzionante del tuo esempio

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

Vedi anche Javascript call () & apply () vs bind ()?


1

Risposta breve:

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

... 

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

1
Questo non funziona correttamente. Se il valore dei tuoi parametri cambia ogni volta che viene impostato il gestore di eventi, produrrà risultati imprevisti perché non si chiude oltre il valore di param1o param2. Se questi valori cambiano, non verranno impostati sul valore che erano durante il tempo in cui è stato creato il gestore dell'evento. Verranno impostati solo sul valore corrente. Inoltre, questo non è diverso dall'impostazione di una variabile al di fuori dell'ambito della funzione listener di eventi e dal riferimento a tale variabile nel gestore di eventi, quindi non esegue affatto il passaggio di parametri.
TetraDev

Non ho davvero capito il tuo punto quindi la mia risposta potrebbe essere sbagliata. Ad ogni modo, il gestore di eventi è impostato una volta (non sempre credo, ma di solito è quello che qualcuno vuole). In secondo luogo, questo dice più o meno che la funzione handler è myfunction e che ha 2 parametri più la variabile "event". In terzo luogo, sì, funziona ei risultati sono esattamente come previsto.
user3093134

1
No, non funziona. L'ho testato esattamente come hai fatto tu e il mio punto rimane valido. Se param1è noodlela prima volta che viene chiamato addEventListener e la seconda volta che lo chiami, paramè cheeseallora che ogni volta che viene attivato il listener di eventi click, param1verrà impostato su cheesee non noodle. Pertanto, non utilizza una "chiusura" per ricordare il valore che esisteva al momento dell'aggiunta del listener di eventi. Ci sono scenari in cui l'ascoltatore di eventi deve essere aggiunto più volte che non devono essere illustrati affinché il mio punto sia valido.
TetraDev

Non sono un esperto e non ho mai sentito parlare di "chiusura" nella programmazione prima, quindi non capisco cosa intendi con questo.
user3093134

2
Grazie per averlo verificato, visiterò sicuramente anche i link che hai pubblicato. Inoltre, devo dire che sei molto gentile e onesto, signore, continua così e buona giornata :)
user3093134

0

thisall'interno di doThingsè l'oggetto finestra. Prova questo invece:

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

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

    return {
        eventHandler: eventHandler
    };
};

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.