removeEventListener на анонимных функциях в JavaScript - PullRequest
83 голосов
/ 09 февраля 2011

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

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 для анонимных функций, но так ли это в этой ситуации?

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

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

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

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

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

Ответы [ 12 ]

91 голосов
/ 17 июля 2012

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

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

РЕДАКТИРОВАТЬ: Это не будет работать, если вы работаете в строгом режиме ("use strict";)

62 голосов
/ 10 февраля 2011

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

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

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);   
37 голосов
/ 27 декабря 2016

Версия решения Otto Nascarella , работающего в строгом режиме:

button.addEventListener('click', function handler() {
      ///this will execute only once
      alert('only once!');
      this.removeEventListener('click', handler);
});
10 голосов
/ 10 апреля 2015
window.document.removeEventListener("keydown", getEventListeners(window.document.keydown[0].listener));  

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

Предупреждение: работает только в Chrome Dev Tools и не может использоваться в коде : ссылка

2 голосов
/ 23 ноября 2018

в современных браузерах вы можете следующее ...

button.addEventListener( 'click', () => {
    alert( 'only once!' );
}, { once: true } );

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters

2 голосов
/ 13 декабря 2015

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

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

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

Node.cloneNode ()

2 голосов
/ 01 января 2013

Не очень анонимный вариант

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 и позволяет легко удалить.

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

Так что метод ( проще ) такой:

element.addEventListener( action, function name () {
    doSomething();
    element.removeEventListener( action, name, capture );
}, capture );
1 голос
/ 01 сентября 2016

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

//one-time fire
element.addEventListener('mousedown', {
  handleEvent: function (evt) {
    element.removeEventListener(evt.type, this, false);
  }
}, false);
1 голос
/ 12 января 2016

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

EventTarget. addEventListener ( event_type , функция-обработчик, Bubbling | Capturing );

Мышь, клавиатура события Пример теста в 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

0 голосов
/ 12 июля 2018

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

/*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', поэтому при таком подходе могут возникнуть некоторые проблемы.

...