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.