2012-05-04 19 views
29

Ho il seguente codice per aggiungere eventListenerJavascript removeEventListener non funziona

area.addEventListener('click',function(event) { 
       app.addSpot(event.clientX,event.clientY); 
       app.addFlag = 1; 
      },true); 

Si sta lavorando correttamente come expected..Later in un'altra funzione ho cercato di rimuovere il listener di eventi utilizzando il seguente codice

area.removeEventListener('click',function(event) { 
       app.addSpot(event.clientX,event.clientY); 
       app.addFlag = 1; 
      },true); 

Ma l'ascoltatore pari non viene rimosso. Perché sta accadendo? C'è qualche problema con il mio removeEventListener()? Nota: Qui zona è qualcosa come document.getElementById ('MyID')

risposta

45

Questo perché due funzioni anonime sono funzioni completamente diverse. L'argomento di removeEventListener non è un riferimento all'oggetto funzione precedentemente collegato.

function foo(event) { 
       app.addSpot(event.clientX,event.clientY); 
       app.addFlag = 1; 
      } 
area.addEventListener('click',foo,true); 
area.removeEventListener('click',foo,true); 
+0

Grazie mille! – Woppi

+9

+1 vero. 'bind (this)' cambierà la firma. Quindi assegna sempre la funzione a 'var' dopo aver vincolato' this' all'utilizzo della funzione 'bind' API in modo che lo stesso' var' possa essere usato in 'removeListener'. Vedrai questo problema più evidente nel dattiloscritto – Nirus

+2

che non ti permetterà di passare parametri di funzione per esempio. 'pippo (1)' – Herrgott

0

per rimuoverla, memorizzare la funzione in una variabile o semplicemente utilizzare una funzione chiamata e passare tale funzione al removeEventListener chiamata:

function areaClicked(event) { 
    app.addSpot(event.clientX, event.clientY); 
    app.addFlag = 1; 
} 

area.addEventListener('click', areaClicked, true); 
// ... 
area.removeEventListener('click', areaClicked, true); 
+0

ma come posso passare argomenti (qui evento) a quella funzione .. Ecco perché ho usato la funzione anonima –

+0

Viene passato dal browser. Non importa se si definisce la funzione separatamente o no. – ThiefMaster

+0

ATTENZIONE: ho scoperto cosa c'era di sbagliato nel mio approccio. Il metodo removeEventListener() funziona SOLO con FUNZIONI NOMINATE. NON funziona con funzioni anonime! Quando ho modificato il codice per tenerne conto, tutto ha funzionato come pianificato. Devi definire una funzione NAMED nella tua chiusura e restituire un riferimento a una sua istanza con i parametri passati dalla chiusura. Fai questo, e removeEventListener() funziona perfettamente. –

0

definire il gestore di eventi prima,

e poi

area.addEventListener('click',handler); 
area.removeEventListener('click',handler); 
2

Si sta creando due diverse funzioni in entrambe le chiamate. Quindi la seconda funzione non si riferisce in alcun modo al primo e il motore è in grado di rimuovere la funzione. Utilizzare invece un identificatore comune per la funzione.

var handler = function(event) { 
       app.addSpot(event.clientX,event.clientY); 
       app.addFlag = 1; 
      }; 
area.addEventListener('click', handler,true); 

successivamente è quindi possibile rimuovere il gestore chiamando

area.removeEventListener('click', handler,true); 
0

Se si vuole passare le variabili locali alla funzione chiamata dal listener di eventi, è possibile definire la funzione all'interno della funzione (per ottenere le variabili locali) e passare il nome della funzione nella funzione stessa. Ad esempio, iniziamo all'interno della funzione che aggiunge il listener di eventi con app come variabile locale. Si potrebbe scrivere una funzione all'interno di questa funzione, ad esempio,

function yourFunction() { 
    var app; 

    function waitListen() { 
     waitExecute(app, waitListen); 
    } 

    area.addEventListener('click', waitListen, true); 
} 

Poi si ha ciò che è necessario rimuoverla quando waitExecute viene chiamato.

function waitExecute (app, waitListen) { 
    ... // other code 
    area.removeEventListener('click', waitListen, true); 
} 
+0

Ho riscontrato un problema qui. Anche se si definisce una funzione di gestore eventi, si salva un riferimento a tale funzione e quindi si passa quel riferimento a removeEventListener() in seguito, la funzione non viene rimossa. Il commento è troppo piccolo per inserire il codice, quindi se vuoi il codice, dovrò usare una casella di risposta ... –

+0

Addendum a quanto sopra: un altro fenomeno interessante che ho trovato, è che anche se specifichi quello il tuo ascoltatore di eventi è passivo, il vecchio persiste ancora nella catena. Peggio ancora, il vecchio ora diventa un gestore di eventi bloccanti, mentre il nuovo mantiene il suo status passivo. Penso che sia necessaria una spiegazione qui. –

0

Ho riscontrato un problema con removeEventListener() che deve essere spiegato.

Volevo essere in grado di passare parametri agli ascoltatori di eventi, così ho scritto una funzione per generare il listener di eventi, che a sua volta restituisce una seconda funzione, che chiama il listener di eventi previsto come callback.

Il file di libreria completa è la seguente:

//Event handler constants 

function EventHandlerConstants() 
{ 
this.SUCCESS = 0; //Signals success of an event handler function 
this.NOTFUNCTION = 1; //actualHandler argument passed to MakeEventHandler() is not a Function object 

//End constructor 
} 

//MakeEventHandler() 

//Arguments: 

//actualHandler : reference to the actual function to be called as the true event handler 

//selfObject : reference to whatever object is intended to be referenced via the "this" keyword within 
//   the true event handler. Set to NULL if no such object is needed by your true 
//   event handler specified in the actualHandler argument above. 

//args  : array containing the arguments to be passed to the true event handler, so that the true 
//   event handler can be written with named arguments, such as: 

//   myEventHandler(event, arg1, arg2, ...) 

//   If your function doesn't need any arguments, pass an empty array, namely [], as the 
//   value of this argument. 

//Usage: 

//c = new EventHandlerConstants(); 
//res = MakeEventHandler(actualHandler, selfObject, args); 
//if (res == c.SUCCESS) 
// element.addEventListener(eventType, res.actualHandler, true); //or whatever 


function MakeEventHandler(actualHandler, selfObject, args) 
{ 
var c = new EventHandlerConstants(); 

var funcReturn = null;  //This will contain a reference to the actual function generated and passed back to 
       //the caller 

var res = { 
     "status" : c.SUCCESS, 
     "actualHandler" : null 
     }; 

if (IsGenuineObject(actualHandler, Function)) 
{ 
    res.actualHandler = function(event) { 

     var trueArgs = [event].concat(args); 

     actualHandler.apply(selfObject, trueArgs); 

    }; 

} 
else 
{ 
    res.status = c.NOTFUNCTION; 

//End if/else 
} 

//Return our result object with appropriate properties set ... 

return(res); 

//End function 
} 

Poi ho scritto una pagina di prova rapida per scoprire se questo ha funzionato come previsto, e mi ha permesso di aggiungere e rimuovere i gestori di eventi a volontà.

pagina di prova

L'HTML è il seguente:

<!DOCTYPE html> 
<html> 
<head> 

<!-- CSS goes here --> 

<link rel="stylesheet" type="text/css" href="NewEventTest.css"> 

<!-- Required JavaScript library files --> 

<script language = "JavaScript" src="BasicSupport.js"></script> 
<script language = "JavaScript" src="EventHandler6.js"></script> 

</head> 

<body class="StdC" id="MainApplication"> 

<button type="button" class="StdC NoSwipe" id="Button1">Try Me Out</button> 

<button type="button" class="StdC NoSwipe" id="Button2">Alter The 1st Button</button> 

</body> 

<script language = "JavaScript" src="NewEventTest.js"></script> 

</html> 

Per completezza, io uso il seguente file semplice CSS così:

/* NewEventTest.css */ 


/* Define standard display settings classes for a range of HTML elements */ 

.StdC { 

color: rgba(255, 255, 255, 1); 
background-color: rgba(0, 128, 0, 1); 
font-family: "Book Antiqua", "Times New Roman", "Times", serif; 
font-size: 100%; 
font-weight: normal; 
text-align: center; 

} 


.NoSwipe { 

user-select: none; /* Stops text from being selectable! */ 

} 

Il codice di prova è la seguente:

//NewEventTest.js 


function GlobalVariables() 
{ 
this.TmpRef1 = null; 
this.TmpRef2 = null; 
this.TmpRef3 = null; 

this.Const1 = null; 

this.Handler1 = null; 
this.Handler2 = null; 
this.Handler3 = null; 

this.EventOptions = {"passive" : true, "capture" : true }; 

//End constructor 
} 


//Button 1 Initial function 

function Button1Initial(event) 
{ 
console.log("Button 1 initial event handler triggered"); 

//End event handler 
} 


function Button1Final(event) 
{ 
console.log("Button 1 final event handler triggered"); 

//End event handler 
} 


function Button2Handler(event, oldFunc, newFunc) 
{ 
var funcRef = null; 

this.removeEventListener("click", oldFunc); 
this.addEventListener("click", newFunc, GLOBALS.EventOptions); 

//End event handler 
} 


//Application Setup 

GLOBALS = new GlobalVariables(); 

GLOBALS.Const1 = new EventHandlerConstants(); 

GLOBALS.TmpRef1 = document.getElementById("Button1"); 
GLOBALS.TmpRef2 = MakeEventHandler(Button1Initial, null, []); 
if (GLOBALS.TmpRef2.status == GLOBALS.Const1.SUCCESS) 
{ 
    GLOBALS.Handler1 = GLOBALS.TmpRef2.actualHandler; 
    GLOBALS.TmpRef1.addEventListener("click", GLOBALS.Handler1, GLOBALS.EventOptions); 

//End if 
} 

GLOBALS.TmpRef1 = MakeEventHandler(Button1Final, null, []); 
if (GLOBALS.TmpRef1.status == GLOBALS.Const1.SUCCESS) 
{ 
    GLOBALS.Handler3 = GLOBALS.TmpRef1.actualHandler; 

//End if 
} 


GLOBALS.TmpRef1 = document.getElementById("Button2"); 
GLOBALS.TmpRef2 = document.getElementById("Button1"); 
GLOBALS.TmpRef3 = Button1Final; 
GLOBALS.TmpRef4 = MakeEventHandler(Button2Handler, GLOBALS.TmpRef2, [GLOBALS.Handler1, GLOBALS.Handler3]); 
if (GLOBALS.TmpRef4.status == GLOBALS.Const1.SUCCESS) 
{ 
    GLOBALS.Handler2 = GLOBALS.TmpRef4.actualHandler; 
    GLOBALS.TmpRef1.addEventListener("click", GLOBALS.Handler2, GLOBALS.EventOptions); 

//End if 
} 

Quindi, il test da eseguire è il seguente:

[1] Allegare un gestore di eventi click al pulsante n. 1;

[2] Verificare se il gestore eventi viene richiamato quando faccio clic sul pulsante;

[3] Una volta superato il test, fare clic sul pulsante n.

I passaggi [1] e [2] funzionano correttamente. Il gestore di eventi è allegato e richiamato ogni volta che clicco sul pulsante.

Il problema riguarda Step [3].

Anche se si salva un riferimento alla funzione generata da MakeEventHandler(), in particolare allo scopo di rimuovere quel listener di eventi nel passaggio [3], la chiamata a removeEventListener() NON rimuove il listener di eventi. Il clic successivo sul pulsante 1 attiva tutti gli ascoltatori di eventi, incluso quello che presumibilmente ho rimosso!

Inutile dire che questo comportamento trovo sconcertante, nonostante l'impostazione con attenzione tutto ciò in modo che la funzione I specificare nella chiamata a removeEventListener() è la stessa funzione di auto ho aggiunto inizialmente con addEventListener() - secondo tutto la documentazione sull'argomento che ho letto (compreso questo thread), passando un riferimento alla stessa funzione per ogni chiamata dovrebbe funzionare, ma chiaramente non lo fa.

Al Passo [1], l'uscita di test nella console legge, come previsto:

Pulsante 1 gestore di eventi iniziale innescato

Il codice è anche funzionare, come previsto, nel passaggio [2], e una traccia passo passo del codice rivela che, in effetti, il codice viene eseguito come previsto.

Ma al punto [3], mentre il prima Fare clic sul pulsante # 1 si ottiene il risultato desiderato:

Pulsante 1 gestore dell'evento finale innescato

cosa succede quando il pulsante 1 si fa clic su successivamente è questo:

Pulsante 1 iniziale gestore di eventi tr iggered Pulsante 1 gestore dell'evento finale innescato

Sicuramente, anche se la funzione inizialmente collegato al pulsante # 1 persiste ancora in memoria, perché è stato generato all'interno di una chiusura, dovrebbe ancora essere staccato dalla raccolta listener di eventi per l'elemento? Perché è ancora connesso?

Oppure ho riscontrato qualche strano bug riguardante l'utilizzo di chiusure con listener di eventi, che deve essere segnalato?

+1

Dovresti fare una nuova domanda. Questa area risponde alla domanda dell'OP. – VectorVortec