¿Cómo eliminarEventListener que es addEventListener con función anónima?

88
function doSomethingWith(param)
{
    document.body.addEventListener(
        'scroll',
        function()
        {
            document.write(param);
        },
        false
    ); // An event that I want to remove later
}
setTimeout(
    function()
    {
        document.body.removeEventListener('scroll', HANDLER ,false);
            // What HANDLER should I specify to remove the anonymous handler above?
    },
    3000
);
doSomethingWith('Test. ');
Japboy
fuente
Posible duplicado de JavaScript: eliminar el detector de eventos
Heretic Monkey

Respuestas:

111

No puedes. Tienes que usar una función nombrada o almacenar la referencia de alguna manera.

var handler;

function doSomethingWith(param) {
    handler = function(){
        document.write(param);
    };  
    document.body.addEventListener('scroll', handler,false);
}
setTimeout(function() {
     document.body.removeEventListener('scroll', handler ,false);
}, 3000);

Lo mejor sería hacerlo de forma estructurada, de modo que pueda identificar diferentes controladores y eliminarlos. En el ejemplo anterior, obviamente solo podría eliminar el último controlador.

Actualizar:

Puede crear su propio controlador de controlador (:)):

var Handler = (function(){
    var i = 1,
        listeners = {};

    return {
        addListener: function(element, event, handler, capture) {
            element.addEventListener(event, handler, capture);
            listeners[i] = {element: element, 
                             event: event, 
                             handler: handler, 
                             capture: capture};
            return i++;
        },
        removeListener: function(id) {
            if(id in listeners) {
                var h = listeners[id];
                h.element.removeEventListener(h.event, h.handler, h.capture);
                delete listeners[id];
            }
        }
    };
}());

Entonces puedes usarlo con:

function doSomethingWith(param) {
    return Handler.addListener(document.body, 'scroll', function() {
        document.write(param);
    }, false);
}

var handler = doSomethingWith('Test. ');

setTimeout(function() {
     Handler.removeListener(handler);
}, 3000);

MANIFESTACIÓN

Felix Kling
fuente
¿Podría explicar qué es la forma estructurada? Mi nivel de inglés no es lo suficientemente bueno para entender eso ... Gracias.
Japboy
1
@Japboy: De nada :) Acabo de notar un pequeño error y lo arreglé.
Felix Kling
¿Por qué envolverías addListener y removeListener?
inútil
@useless: ¿Te refieres a la función de autoinvocación? Para mantener iy listeners"privado".
Felix Kling
2
@Bergi: Hecho. Avísame si me perdí algo.
Felix Kling
11

No puede, necesita una referencia a la función:

function doSomethingWith(param) {
   var fn = function(){ document.write(param); };
   document.body.addEventListener('scroll', fn, false);
   setTimeout(function(){ document.body.removeEventListener('scroll', fn, false); }, 3000);
}
doSomethingWith('Test. ');
davin
fuente
¿Cómo se pasa el objeto de evento?
slier
@sliervar fn = function(event){ document.write(param); };
cychoi
5

También puedes hacer esto así:

const ownAddEventListener = (scope, type, handler, capture) => {
  scope.addEventListener(type, handler, capture);
  return () => {
    scope.removeEventListener(type, handler, capture);    
  }
}

Entonces puede eliminar el detector de eventos de esta manera:

// Add event listener
const disposer = ownAddEventListener(document.body, 'scroll', () => { 
  // do something
}, false);

// Remove event listener
disposer();
Simon Jentsch
fuente
¿Es posible determinar qué eventos se han vinculado al objeto de esta manera?
Frumbert
Se podía añadir algunas propiedades de la función, como el tipo, alcance, etc.const disposerFn = () => { scope.removeEventListener(type, handler, capture); } disposerFn.type = type; return disposerFn;
Simon Jentsch
1

si no tiene que admitir IE, puede usar la opción una vez

[Element].addEventListener('click', () => {...}, {
  capture: false,
  once: true
});
manoi
fuente