Ich habe ein Problem mit removeEventListener () festgestellt, das erklärt werden muss.
Ich wollte in der Lage sein, Parameter an Ereignis-Listener zu übergeben, also schrieb ich eine Funktion zum Generieren des Ereignis-Listeners, die wiederum eine zweite Funktion zurückgibt, die meinen beabsichtigten Ereignis-Listener als Rückruf aufruft.
Die vollständige Bibliotheksdatei lautet wie folgt:
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);
}
Dann schrieb ich eine kurze Testseite, um herauszufinden, ob dies wie beabsichtigt funktionierte, und erlaubte mir, Ereignishandler nach Belieben hinzuzufügen UND zu entfernen.
Die HTML-Testseite lautet wie folgt:
<!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>
Der Vollständigkeit halber verwende ich auch die folgende einfache CSS-Datei:
.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;
}
Der Testcode lautet wie folgt:
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);
}
Der durchzuführende Test ist also wie folgt:
[1] Fügen Sie einen Klickereignishandler zu Schaltfläche 1 hinzu.
[2] Testen Sie, ob der Ereignishandler aufgerufen wird, wenn ich auf die Schaltfläche klicke.
[3] Wenn dieser Test bestanden ist, klicken Sie auf Schaltfläche 2 und rufen Sie den daran angehängten Ereignishandler auf, der den alten Ereignishandler entfernt, der an Schaltfläche 1 angehängt ist, und ihn dann durch einen neuen Ereignishandler ersetzt.
Die Schritte [1] und [2] funktionieren einwandfrei. Der Ereignishandler wird angehängt und aufgerufen, wenn ich auf die Schaltfläche klicke.
Das Problem liegt bei Schritt [3].
Obwohl ich einen Verweis auf die von MakeEventHandler () generierte Funktion speichere, insbesondere um diesen Ereignis-Listener in Schritt [3] zu entfernen, entfernt der Aufruf von removeEventListener () den Ereignis-Listener NICHT. Das anschließende Klicken auf Button # 1 löst BEIDE Ereignis-Listener aus, einschließlich desjenigen, den ich angeblich entfernt habe!
Unnötig zu erwähnen, dass dieses Verhalten ich rätselhaft finde, obwohl ich alles sorgfältig so eingerichtet habe, dass die Funktion, die ich im Aufruf von removeEventListener () angegeben habe, dieselbe Funktion ist, die ich ursprünglich mit addEventListener () hinzugefügt habe - gemäß der gesamten Dokumentation zu diesem Thema I. Ich habe gelesen (einschließlich dieses Threads), dass die Übergabe eines Verweises auf dieselbe Funktion für jeden Aufruf funktionieren sollte , aber eindeutig nicht.
In Schritt [1] lautet die Testausgabe in der Konsole wie erwartet:
Die erste Ereignishandler-Taste 1 wurde ausgelöst
Der Code wird erwartungsgemäß auch in Schritt [2] ausgeführt, und eine schrittweise Verfolgung des Codes zeigt, dass der Code tatsächlich wie erwartet ausgeführt wird.
Aber in Schritt [3], während der erste Klick auf Button # 1 das gewünschte Ergebnis liefert:
Die letzte Ereignisbehandlungsroutine für Schaltfläche 1 wird ausgelöst
Was passiert, wenn anschließend auf Schaltfläche 1 geklickt wird, ist Folgendes :
Der erste Ereignishandler von Schaltfläche 1 wurde ausgelöst. Der letzte Ereignishandler von Schaltfläche 1 wurde ausgelöst
Selbst wenn die ursprünglich an Schaltfläche 1 angehängte Funktion im Speicher verbleibt, weil sie innerhalb eines Abschlusses generiert wurde, sollte sie dennoch von der Ereignis-Listener-Sammlung für das Element getrennt werden. Warum ist es noch verbunden?
Oder bin ich auf einen seltsamen Fehler gestoßen, bei dem Schließungen mit Ereignis-Listenern verwendet wurden, der gemeldet werden muss?