removeEventListener для анонимных функций в JavaScript

у меня есть объект, в котором есть методы. Эти методы помещаются в объект внутри анонимной функции. Выглядит это так:

var t = {};
window.document.addEventListener("keydown", function(e) {
    t.scroll = function(x, y) {
        window.scrollBy(x, y);
    };
    t.scrollTo = function(x, y) {
        window.scrollTo(x, y);
    };
});  

(существует гораздо больше кода, но этого достаточно, чтобы показать проблему)

теперь я хочу остановить прослушиватель событий в некоторых случаях. Поэтому я пытаюсь сделать removeEventListener, но я не могу понять, как это сделать. Я читал в других вопросах, что невозможно вызвать removeEventListener на anonymous функции, но так ли это в данной ситуации?

у меня есть метод в t, созданный внутри анонимной функции, и поэтому я думал, что это возможно. Выглядит так:

t.disable = function() {
    window.document.removeEventListener("keydown", this, false);
}

почему я не могу сделать это?

есть ли другой (хороший) способ сделать это?

Бонусная информация; это должно работать только в Safari, следовательно, отсутствует поддержка ie.

11 ответов


Я считаю, что это точка анонимной функции, ей не хватает имени или способа ссылаться на нее.

на вашем месте я бы просто создал именованную функцию или поместил ее в переменную, чтобы у вас была ссылка на нее.

var t = {};
var handler = function(e) {
    t.scroll = function(x, y) {
        window.scrollBy(x, y);
    };
    t.scrollTo = function(x, y) {
        window.scrollTo(x, y);
    };
};
window.document.addEventListener("keydown", handler);

затем вы можете удалить его с помощью

window.document.removeEventListener("keydown", handler);   

Если вы находитесь внутри фактической функции, вы можете использовать аргументы.вызываемый в качестве ссылки на функцию. как в:

button.addEventListener('click', function() {
      ///this will execute only once
      alert('only once!');
      this.removeEventListener('click', arguments.callee);
});

EDIT: Это не будет работать, если вы работаете в строгом режиме ("use strict";)


версия Отто Nascarellaрешение, которое работает в строгом режиме:

button.addEventListener('click', function handler() {
      ///this will execute only once
      alert('only once!');
      this.removeEventListener('click', handler);
});

window.document.removeEventListener("keydown", getEventListeners(window.document.keydown[0].listener));  

может быть несколько анонимных функций, keydown[1]


не такой анонимный вариант

element.funky = function() {
    console.log("Click!");
};
element.funky.type = "click";
element.funky.capt = false;
element.addEventListener(element.funky.type, element.funky, element.funky.capt);
// blah blah blah
element.removeEventListener(element.funky.type, element.funky, element.funky.capt);

С момента получения обратной связи от Энди (совершенно верно, но, как и во многих примерах, я хотел показать контекстное расширение идеи) здесь менее сложным экспозиция:

<script id="konami" type="text/javascript" async>
    var konami = {
        ptrn: "38,38,40,40,37,39,37,39,66,65",
        kl: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
    };
    document.body.addEventListener( "keyup", function knm ( evt ) {
        konami.kl = konami.kl.slice( -9 );
        konami.kl.push( evt.keyCode );
        if ( konami.ptrn === konami.kl.join() ) {
            evt.target.removeEventListener( "keyup", knm, false );

            /* Although at this point we wish to remove a listener
               we could easily have had multiple "keyup" listeners
               each triggering different functions, so we MUST
               say which function we no longer wish to trigger
               rather than which listener we wish to remove.

               Normal scoping will apply to where we can mention this function
               and thus, where we can remove the listener set to trigger it. */

            document.body.classList.add( "konami" );
        }
    }, false );
    document.body.removeChild( document.getElementById( "konami" ) );
</script>

Это позволяет эффективно анонимную структуру функций, избегает использования практически устаревший callee, и позволяет легко удаление.

кстати: удаление элемента сценария сразу после установки слушателя-милый трюк для скрытия кода, который предпочел бы не был совершенно очевидным для посторонних глаз (испортил бы сюрприз ;-)

поэтому метод (проще) составляет:

element.addEventListener( action, function name () {
    doSomething();
    element.removeEventListener( action, name, capture );
}, capture );

Это не идеально, поскольку он удаляет все, но может работать для ваших нужд:

z = document.querySelector('video');
z.parentNode.replaceChild(z.cloneNode(1), z);

клонирование узла копирует все его атрибуты и их значения, включая встроенные (встроенные) слушатели. Он не копирует прослушиватели событий, добавленные с помощью addEventListener ()

узел.cloneNode ()


JavaScript: addEventListener метод регистрирует указанный прослушиватель в EventTarget (Element|document / Window), который он вызывает.

eventtarget из.addEventListener(тип, handler_function,Клокотать|Захвата);

Мышь, Клавиатура событий пример теста в WebConsole:

var keyboard = function(e) {
    console.log('Key_Down Code : ' + e.keyCode);
};
var mouseSimple = function(e) {
    var element = e.srcElement || e.target;
    var tagName = element.tagName || element.relatedTarget;
    console.log('Mouse Over TagName : ' + tagName);    
};
var  mouseComplex = function(e) {
    console.log('Mouse Click Code : ' + e.button);
} 

window.document.addEventListener('keydown',   keyboard,      false);
window.document.addEventListener('mouseover', mouseSimple,   false);
window.document.addEventListener('click',     mouseComplex,  false);

removeEventListener метод удаляет прослушиватель событий, ранее зарегистрированный в EventTarget.addEventListener ().

window.document.removeEventListener('keydown',   keyboard,     false);
window.document.removeEventListener('mouseover', mouseSimple,  false);
window.document.removeEventListener('click',     mouseComplex, false);

caniuse


чтобы дать более современный подход к этому:

//one-time fire
element.addEventListener('mousedown', {
  handleEvent: function (evt) {
    element.removeEventListener(evt.type, this, false);
  }
}, false);

возможно, не лучшее решение с точки зрения того, что вы просите. Я все еще не определил эффективный метод удаления анонимной функции, объявленной встроенной с вызовом прослушивателя событий.

Я лично использую переменную для хранения <target> и объявить функцию вне вызова прослушивателя событий, например:

const target = document.querySelector('<identifier>');

function myFunc(event) { function code; }

target.addEventListener('click', myFunc);

затем удалить слушатель:

target.removeEventListener('click', myFunc);

Не верхняя рекомендация, которую вы получите, но удалить анонимные функции единственное решение, которое я нашел полезным, - удалить, а затем заменить элемент HTML. Я уверен, что должен быть лучший метод vanilla JS, но я его еще не видел.


я наткнулся на ту же проблему, и это было лучшее решение, я мог бы получить:

/*Adding the event listener (the 'mousemove' event, in this specific case)*/
element.onmousemove = function(event) {
    /*do your stuff*/
};
/*Removing the event listener*/
element.onmousemove = null;

пожалуйста, имейте в виду, что я только проверил это для window элемент и 'mousemove' событие, поэтому могут быть некоторые проблемы с этим подходом.


window.document.onkeydown = function(){};