我有以下代码来添加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')
答案 0 :(得分:77)
这是因为两个匿名函数是完全不同的函数。您的removeEventListener
参数不是对先前附加的函数对象的引用。
function foo(event) {
app.addSpot(event.clientX,event.clientY);
app.addFlag = 1;
}
area.addEventListener('click',foo,true);
area.removeEventListener('click',foo,true);
答案 1 :(得分:3)
您在两个调用中都创建了两个不同的函数。因此第二个函数与第一个函数没有任何关系,并且引擎能够删除该函数。请改为使用该功能的通用标识符。
var handler = function(event) {
app.addSpot(event.clientX,event.clientY);
app.addFlag = 1;
};
area.addEventListener('click', handler,true);
稍后您可以通过调用
删除处理程序area.removeEventListener('click', handler,true);
答案 2 :(得分:1)
要删除它,将函数存储在变量中或只是使用命名函数并将该函数传递给removeEventListener
调用:
function areaClicked(event) {
app.addSpot(event.clientX, event.clientY);
app.addFlag = 1;
}
area.addEventListener('click', areaClicked, true);
// ...
area.removeEventListener('click', areaClicked, true);
答案 3 :(得分:1)
如果要将局部变量传递给事件侦听器调用的函数,可以在函数内部定义函数(以获取局部变量)并在函数本身中传递函数的名称。例如,让我们在使用app作为局部变量添加事件监听器的函数内部启动。您可以在此函数中编写一个函数,例如
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);
}
答案 4 :(得分:1)
我发现对于windows对象,最后一个参数" true"是必须的。 如果没有捕获标记,则删除不起作用。
答案 5 :(得分:0)
首先定义您的事件处理程序,
然后
area.addEventListener('click',handler);
area.removeEventListener('click',handler);
答案 6 :(得分: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]将Click事件处理程序附加到Button#1;
[2]测试单击按钮时是否调用事件处理程序;
[3]一旦测试通过,单击Button#2,并调用附加到其上的事件处理程序,这将删除附加到Button#1的旧事件处理程序,然后用新的事件处理程序替换它。
步骤[1]和[2]工作正常。事件处理程序已附加,每当我单击按钮时都会调用它。
问题在于步骤[3]。
即使我保存了对MakeEventHandler()生成的函数的引用,特别是为了在Step [3]中删除该事件监听器,对removeEventListener()的调用也不会删除事件监听器。随后点击按钮#1会触发两个事件监听器,包括我应该删除的那个!
毋庸置疑,我发现这个行为令人费解,尽管仔细设置了所有内容,以便我在removeEventListener()调用中指定的函数是我最初使用addEventListener()添加的自相同函数 - 根据所有关于我已阅读过的主题的文档(包括此主题),为每次调用传递对同一函数的引用应该有效,但显然不会。< / p>
在步骤[1],控制台中的测试输出按预期读取:
按钮1初始事件处理程序已触发
代码也按预期在步骤[2]中运行,并且逐步跟踪代码显示代码确实按预期执行。
但是在步骤[3]中,当第一次点击按钮#1时会产生所需的结果:
按钮1最终事件处理程序已触发
单击按钮#1 后续时会发生什么:
按钮1初始事件处理程序已触发 按钮1最终事件处理程序已触发
当然,即使最初附加到Button#1的函数仍然存在于内存中,因为它是在闭包内生成的,它仍然应该从元素的事件监听器集合中分离出来?为什么它仍然连接?
或者我遇到过一些涉及使用事件监听器闭包的奇怪错误,需要报告吗?
答案 7 :(得分:0)
这是我最终要做的,但它在一个路由类中,但应该没有太大区别,我希望事件侦听器不要在每次调用 afterModel() 时累积,但还需要参数和范围,以便模型是每次都变了。
export default class iFrameRoute extends Route {
afterModel(model) {
this.initFrame = function(event) {
alert("I am being called");
window.removeEventListener("message", this.route.test);
}.bind({route: this, data: model});
window.addEventListener("message", this.initFrame );
}
}
答案 8 :(得分:0)
我有一个数据分页系统,这个函数提供了很多信息来创建表和插入新寄存器,所以,在任何导航中我必须在添加按钮上添加一个事件监听器,我发现最好的方法是销毁元素并重新创建在添加事件侦听器之前,这对我来说很好
答案 9 :(得分:0)
在 React 函数组件中,确保使用 useCallback(() => {}
钩子定义回调。如果不这样做,每次重新渲染时回调都会不同,removeEventListener
方法将不起作用。
const scrollCallback = useCallback(() => { // do sth. }
window.addEventListener("scroll", scrollCallback, true);
window.removeEventListener("scroll", scrollCallback, true);