我遇到了需要说明的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()最初添加的自同函数,尽管我对此进行了仔细的设置,但我还是感到困惑-根据有关该主题的所有文档已经读过(包括该线程),每次调用都传递对同一函数的引用应该可以,但显然不行。
在步骤[1]中,控制台中的测试输出按预期读取:
按钮1初始事件处理程序已触发
该代码还将按预期方式在步骤[2]中运行,并且逐步跟踪该代码可发现,确实,该代码已按预期执行。
但是在步骤[3]中,第一次单击按钮#1会产生所需的结果:
按钮1最终事件处理程序已触发
随后单击按钮#1时会发生以下情况:
按钮1初始事件处理程序已触发按钮1最终事件处理程序已触发
当然,即使最初附加于Button#1的函数仍然保留在内存中,因为它是在闭包中生成的,仍应将其与元素的事件侦听器集合分离吗?为什么仍然连接?
还是我遇到了一些奇怪的错误,其中涉及将闭包与事件侦听器一起使用,需要进行报告?