Javascript removeEventListener не працює


80

У мене є такий код, щоб додати eventListener

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

Він працює належним чином належним чином .. Пізніше в іншій функції я спробував видалити прослуховувач подій, використовуючи наступний код

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

Але навіть слухач не видаляється .. Чому це відбувається? Чи є якісь проблеми з моїм removeEventListener ()? Примітка: Тут знаходиться щось на зразок document.getElementById ('myId')


Відповіді:


129

Це тому, що дві анонімні функції - це абсолютно різні функції. removeEventListenerАргумент вашого не є посиланням на об'єкт функції, який раніше був приєднаний.

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

1
Дуже дякую!
— Воппі

55
+1 правда. bind(this)змінить підпис. Тому завжди призначайте функцію a varпісля прив’язки thisдо використання bindAPI функції, щоб вона varмогла бути використана в removeListener. Ви побачите цю проблему більш очевидною в машинописі
— Nirus 28.03.17

4
Це не дозволить вам передавати параметри функції fefoo(1)
— Herrgott

2
спасибі за не є посиланням на об'єкт функції, який раніше був приєднаний
— Evhz,

18
Якщо хтось використовує класи, спробуйте щось на зразок this.onClick = this.onClick.bind(this)будь-якого слухача, то btn.addEventListener('click', this.onClick), нарешті,btn.removeEventListener('click', this.onClick)
— joseluisq

13

Я вважаю, що для об'єкта windows потрібен останній параметр "true". Видалення не працює, якщо немає прапора захоплення.


Виправлено мою проблему. Дякую.
— Джеймс Манес

7

Ви створюєте дві різні функції в обох викликах. Отже, друга функція жодним чином не відноситься до першої, і двигун може видалити цю функцію. Замість цього використовуйте загальний ідентифікатор функції.

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

пізніше ви можете видалити обробник, зателефонувавши

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

1

Щоб видалити його, збережіть функцію у змінній або просто використовуйте названу функцію та передайте цю функцію removeEventListenerвиклику:

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

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

1
але як я можу передати аргументи (тут подія) цій функції .. Ось чому я використав анонімну функцію
— Jinu Joseph Daniel

Він передається браузером. Неважливо, визначаєте ви функцію окремо чи ні.
— ThiefMaster

ПОПЕРЕДЖЕННЯ: Я з’ясував, що не так із моїм підходом. Метод removeEventListener () працює ТІЛЬКИ з НАЗВАНИМИ ФУНКЦІЯМИ. Він НЕ працює з анонімними функціями! Коли я відредагував код, щоб це врахувати, все працювало, як планувалося. Вам потрібно визначити функцію NAMED у вашому закритті та повернути посилання на його екземпляр із параметрами, переданими закриттям. Зробіть це, і removeEventListener () відмінно працює.
— Девід Едвардс

1

Якщо ви хочете передати локальні змінні функції, яку викликає прослуховувач подій, ви можете визначити функцію всередині функції (щоб отримати локальні змінні) і передати ім'я функції в самій функції. Наприклад, давайте почнемо всередині функції, яка додає прослуховувач подій з додатком як локальною змінною. Ви можете написати функцію всередині цієї функції, таку як,

function yourFunction () {
    var app;

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

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

Тоді у вас є те, що вам потрібно, щоб видалити його, коли викликається waitExecute.

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

Я зіткнувся з проблемою тут. Навіть якщо ви визначите функцію обробника подій, збережіть посилання на цю функцію, а потім передайте це посилання removeEventListener () пізніше, функція не буде видалена. Коментар замалий для розміщення коду, тому, якщо ви хочете код, мені доведеться використати вікно відповіді ...
— Девід Едвардс

Додаток до вищезазначеного: ще одне цікаве явище, яке я виявив, полягає в тому, що навіть якщо ви вказали, що ваш прослуховувач подій пасивний, старий все ще зберігається в ланцюжку. Гірше того, що старий тепер стає обробником подій, що блокують, тоді як новий зберігає свій пасивний статус. Думаю, тут потрібне пояснення.
— Девід Едвардс

0

спочатку визначте свій обробник подій,

і потім

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

0

Я зіткнувся з проблемою з removeEventListener (), яка потребує пояснення.

Я хотів мати можливість передавати параметри прослуховувачам подій, тому я написав функцію для генерації прослуховувача подій, яка, у свою чергу, повертає другу функцію, яка викликає мій передбачуваний прослуховувач подій як зворотний виклик.

Повний файл бібліотеки такий:

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

Потім я написав швидку тестову сторінку, щоб з’ясувати, чи це працює належним чином, і дозволив додати І видалити обробники подій за бажанням.

Тестова сторінка HTML така:

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

Для повноти я також використовую такий простий файл CSS:

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

}

Тестовий код такий:

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

Отже, тест, який потрібно виконати, такий:

[1] Прикріпіть обробник події кліку до кнопки №1;

[2] Перевірте, чи не викликається обробник події, коли я натискаю кнопку;

[3] Після того, як цей тест пройдено, натисніть кнопку №2 і запустите обробник подій, приєднаний до нього, який видаляє старий обробник події, прикріплений до кнопки №1, а потім замінює його новим обробником подій.

Етапи [1] та [2] працюють нормально. Обробник подій приєднується і викликається, коли я натискаю кнопку.

Проблема в кроці [3].

Навіть незважаючи на те, що я зберігаю посилання на функцію, згенеровану MakeEventHandler (), зокрема з метою видалення цього прослуховувача подій на кроці [3], виклик removeEventListener () НЕ видаляє прослуховувач подій. Подальше клацання на кнопці # 1 спрацьовує ОБИХ слухачів подій, включаючи того, якого я нібито видалив!

Само собою зрозуміло, що ця поведінка мене бентежить, незважаючи на ретельну настройку всього, щоб функція, яку я вказую у виклику removeEventListener (), була самою функцією, яку я додав спочатку з addEventListener () - згідно з усією документацією по предмету I Прочитав (включаючи цей потік), передаючи посилання на одну і ту ж функцію для кожного виклику, це має працювати, але явно ні.

На етапі [1] тестовий результат на консолі, як очікується, читає:

Кнопка 1 спрацьовує початковий обробник події

Код також запускається, як і очікувалося, на кроці [2], і поетапна трасування коду показує, що дійсно, код виконується належним чином.

Але на кроці [3], тоді як перший клік на кнопці №1 дає бажаний результат:

Запущено обробник остаточної події кнопки 1

що відбувається після натискання кнопки №1 наступним чином:

Запущений обробник початкової події кнопки 1 Запущений обробник кінцевої події кнопки 1

Звичайно, навіть якщо функція, спочатку приєднана до кнопки №1, все ще зберігається в пам'яті, оскільки вона була згенерована в рамках закриття, її все одно слід від'єднати від колекції прослуховувача подій для елемента? Чому це все ще пов’язано?

Або я зіткнувся з якоюсь дивною помилкою, пов’язаною із використанням закриття з прослуховувачами подій, про яку потрібно повідомити?


2
Вам слід задати нове запитання. Ця область відповідає на запитання ОП.
— VectorVortec

Я теж натрапив на це. Це нісенітниця. Довелося вдаватися до брудних методів обійтися, тобто. відстеження, які події слід увімкнути / вимкнути в об’єкті вікна.
— Mave
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.