Я зіткнувся з проблемою з removeEventListener (), яка потребує пояснення.
Я хотів мати можливість передавати параметри прослуховувачам подій, тому я написав функцію для генерації прослуховувача подій, яка, у свою чергу, повертає другу функцію, яка викликає мій передбачуваний прослуховувач подій як зворотний виклик.
Повний файл бібліотеки такий:
function EventHandlerConstants()
{
this.SUCCESS = 0;
this.NOTFUNCTION = 1;
}
function MakeEventHandler(actualHandler, selfObject, args)
{
var c = new EventHandlerConstants();
var funcReturn = null;
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;
}
return(res);
}
Потім я написав швидку тестову сторінку, щоб з’ясувати, чи це працює належним чином, і дозволив додати І видалити обробники подій за бажанням.
Тестова сторінка HTML така:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="NewEventTest.css">
<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:
.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;
}
Тестовий код такий:
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 };
}
function Button1Initial(event)
{
console.log("Button 1 initial event handler triggered");
}
function Button1Final(event)
{
console.log("Button 1 final event handler triggered");
}
function Button2Handler(event, oldFunc, newFunc)
{
var funcRef = null;
this.removeEventListener("click", oldFunc);
this.addEventListener("click", newFunc, GLOBALS.EventOptions);
}
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);
}
GLOBALS.TmpRef1 = MakeEventHandler(Button1Final, null, []);
if (GLOBALS.TmpRef1.status == GLOBALS.Const1.SUCCESS)
{
GLOBALS.Handler3 = GLOBALS.TmpRef1.actualHandler;
}
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);
}
Отже, тест, який потрібно виконати, такий:
[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, все ще зберігається в пам'яті, оскільки вона була згенерована в рамках закриття, її все одно слід від'єднати від колекції прослуховувача подій для елемента? Чому це все ще пов’язано?
Або я зіткнувся з якоюсь дивною помилкою, пов’язаною із використанням закриття з прослуховувачами подій, про яку потрібно повідомити?