2012-05-04 14 views
29

tengo el siguiente código para agregar eventListenerJavascript removeEventListener no trabajar

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

Está funcionando correctamente como expected..Later en otra función i trató de retirar el detector de eventos usando el siguiente código

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

Pero el oyente par no se elimina ... ¿Por qué está pasando? ¿Hay algún problema con mi removeEventListener()? Nota: Aquí zona es algo así como document.getElementById ('myId')

Respuesta

45

Esto se debe a que dos funciones anónimas son funciones completamente diferentes. El argumento removeEventListener no es una referencia al objeto de función que se adjuntó anteriormente.

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

¡Muchas gracias! – Woppi

+9

+1 Es cierto. 'bind (this)' cambiará la firma. Por lo tanto, siempre asigne la función a 'var' después de vincular' this' a la función 'bind' API para que se pueda usar la misma' var' en 'removeListener'. Verá este problema más evidente en el mecanografiado – Nirus

+2

que no le permitirá pasar los parámetros de la función, es decir, 'foo (1)' – Herrgott

0

para quitarlo, almacenar la función en una variable o simplemente utilizar una función llamada y pasar esa función a la removeEventListener llamada:

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

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

pero ¿cómo puedo pasar argumentos (aquí evento) a esa función ... Es por eso que utilicé la función anónima –

+0

Se pasa por el navegador. No importa si define la función por separado o no. – ThiefMaster

+0

ADVERTENCIA: descubrí lo que estaba mal con mi enfoque. El método removeEventListener() SÓLO funciona con FUNCIONES NOMBRADAS. ¡NO funciona con funciones anónimas! Cuando edité el código para tener esto en cuenta, todo funcionó según lo planeado. Debe definir una función NOMBRADA en su cierre y devolver una referencia a una instancia de la misma con los parámetros aprobados por el cierre. Haga esto y removeEventListener() funciona perfectamente. –

0

definir el controlador de eventos en primer lugar,

y luego

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

Estás creando dos funciones diferentes en las dos llamadas. Entonces, la segunda función no se relaciona de ninguna manera con la primera y el motor puede eliminar la función. Use un identificador común para la función en su lugar.

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

más adelante, se puede quitar el controlador llamando

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

Si desea pasar variables locales de la función llamada por el detector de eventos, puede definir la función dentro de la función (para obtener las variables locales) y pasan el nombre de la función en la función misma. Por ejemplo, comencemos dentro de la función que agrega el detector de eventos con la aplicación como una variable local. Se podría escribir una función dentro de esta función por ejemplo,

function yourFunction() { 
    var app; 

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

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

entonces usted tiene lo que hay que quitarlo cuando waitExecute se llama.

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

He encontrado un problema aquí. Incluso si define una función de controlador de eventos, guarda una referencia a esa función y luego pasa esa referencia a removeEventListener() más tarde, la función no se elimina. El comentario es demasiado pequeño para publicar el código, así que si quieres código, tendré que usar un cuadro de respuesta ... –

+0

Adición a lo anterior: otro fenómeno interesante que he encontrado, es que incluso si especificas eso el oyente de su evento es pasivo, el anterior todavía persiste en la cadena. Peor aún, el antiguo se convierte en un controlador de eventos de bloqueo, mientras que el nuevo mantiene su estado pasivo. Creo que se necesita una explicación aquí. –

0

que he encontrado un problema con removeEventListener() que necesita ser explicado.

Quería poder pasar parámetros a los detectores de eventos, así que escribí una función para generar el detector de eventos, que a su vez devuelve una segunda función, que llama a mi receptor de eventos previsto como una devolución de llamada.

El archivo de biblioteca completa es la siguiente:

//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 
} 

Entonces me escribió una página de prueba rápida para averiguar si esto funcionó como se esperaba, y me ha permitido añadir y eliminar controladores de eventos a voluntad.

página de prueba

El HTML es el siguiente:

<!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> 

Para completar, utilizo el siguiente simple de archivos CSS, así:

/* 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! */ 

} 

El código de prueba es el siguiente:

//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 
} 

Por lo tanto, la prueba a realizar es el siguiente:

[1] Adjunte un controlador de evento click al Botón # 1;

[2] Prueba para ver si el controlador de eventos se invoca cuando hago clic en el botón;

[3] Una vez que se aprueba la prueba, haga clic en el botón n. ° 2 e invoque el controlador de eventos adjunto, que elimina el antiguo controlador de eventos adjunto al botón n. ° 1 y lo reemplaza con un nuevo controlador de eventos.

Los pasos [1] y [2] funcionan bien. El controlador de eventos se adjunta e invoca cada vez que hago clic en el botón.

El problema es con el Paso [3].

Aunque guardo una referencia a la función generada por MakeEventHandler(), específicamente con el propósito de eliminar ese detector de eventos en el Paso [3], la llamada a removeEventListener() NO elimina el detector de eventos. Al hacer clic en el botón n. ° 1, se apagan AMBOS detectores de eventos, incluido el que supuestamente eliminé.

hace falta decir que este comportamiento me parece desconcertante, a pesar de marcar todo cuidadosamente de modo que la función que especifica en la llamada a removeEventListener() es la misma función de auto añadí inicialmente con addEventListener() - de acuerdo con todo la documentación sobre el tema que he leído (incluido este hilo), pasando una referencia a la misma función para cada llamada debería funcionar, pero claramente no.

En el Paso [1], la salida de prueba en la consola lee, como se esperaba:

Botón 1 controlador de eventos inicial desencadena

El código también es correr, como era de esperar, en el paso [2], y un rastro paso a paso del código revela que, de hecho, el código se ejecuta como se esperaba.

pero en el paso [3], mientras que el primera clic en el botón # 1 produce el resultado deseado:

Botón 1 manejador de evento final provocó

lo que sucede cuando el botón # 1 se hace clic en posteriormente es esto:

Botón 1 gestor de eventos inicial tr iggered Botón 1 manejador de evento final provocó

Sin duda, incluso si la función fijada inicialmente para el botón # 1 todavía persiste en la memoria, ya que se genera dentro de un cierre, que aún debe ser separado de la colección de detector de eventos para ¿el elemento? ¿Por qué todavía está conectado?

¿O me he encontrado alguna extraña falla que implica el uso de cierres con detectores de eventos, eso necesita ser informado?

+1

Debería hacer una nueva pregunta. Esta área responde la pregunta del OP. – VectorVortec