97

我有以下代码来添加 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')

4

13 回答 13

163

这是因为这两个匿名函数是完全不同的函数。您removeEventListener的参数不是对先前附加的函数对象的引用。

function foo(event) {
              app.addSpot(event.clientX,event.clientY);
              app.addFlag = 1;
          }
 area.addEventListener('click',foo,true);
 area.removeEventListener('click',foo,true);
于 2012-05-04T06:56:58.580 回答
19

我发现对于 windows 对象,最后一个参数“true”是必需的。如果没有捕获标志,则删除不起作用。

于 2018-06-05T14:44:34.783 回答
7

您在两个调用中创建了两个不同的函数。所以第二个函数与第一个函数没有任何关系,引擎能够删除该函数。请改用函数的通用标识符。

var handler = function(event) {
              app.addSpot(event.clientX,event.clientY);
              app.addFlag = 1;
          };
area.addEventListener('click', handler,true);

稍后您可以通过调用删除处理程序

area.removeEventListener('click', handler,true);
于 2012-05-04T06:57:54.797 回答
7

在 React 函数组件中,确保使用useCallback(() => {}钩子定义回调。如果您不这样做,则每次重新渲染时回调将是不同的,并且该removeEventListener方法将不起作用。

const scrollCallback = useCallback(() => { // do sth. }
window.addEventListener("scroll", scrollCallback, true);
window.removeEventListener("scroll", scrollCallback, true);
于 2021-06-17T08:12:26.623 回答
4

要删除它,请将函数存储在变量中,或者简单地使用命名函数并将该函数传递给removeEventListener调用:

function areaClicked(event) {
    app.addSpot(event.clientX, event.clientY);
    app.addFlag = 1;
}

area.addEventListener('click', areaClicked, true);
// ...
area.removeEventListener('click', areaClicked, true);
于 2012-05-04T06:56:32.267 回答
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);
}
于 2016-03-22T20:55:25.887 回答
0

首先定义您的事件处理程序,

接着

area.addEventListener('click',handler);
area.removeEventListener('click',handler);
于 2012-05-04T06:57:05.283 回答
0

同时在数组中添加函数存储并删除通过映射为我工作

const [functionObjects, setfunctionObjects] = useState([]);

const addListener = (beforeUnloadListener) =>{ setfunctionObjects([...nano, beforeUnloadListener]); addEventListener("beforeunload", beforeUnloadListener, {capture: true}); };

const removeListener = (beforeUnloadListener) => { functionObjects.map((item) => { removeEventListener("beforeunload", item, {capture: true});});};

于 2022-01-31T05:53:51.003 回答
0

如果您在 react js 的功能组件中遇到删除事件侦听器的问题,那么每次重新渲染时都会出现问题函数引用 get 的更改,并且当您尝试删除它时,它的引用引用已经更改,这不允许您删除该事件侦听器。react 提供钩子来保持函数的引用,即使功能组件多次重新渲染。将事件侦听器回调函数包装在 useCallback 钩子中,并且它的引用保持不变,即使函数重新渲染多次

const function = useCallback((e) => {

}, [])
于 2021-09-08T14:05:21.987 回答
0

似乎没有人涵盖 JavaScript 规范的部分内容,该部分现在为您提供了一种机制,可以在使用removeEventListener. 如果我们查看https://dom.spec.whatwg.org/#concept-event-listener,我们会看到有许多属性可以传递给控制事件监听:

{
    type (a string)
    callback (null or an EventListener object)
    capture (a boolean, initially false)
    passive (a boolean, initially false)
    once (a boolean, initially false)
    signal (null or an AbortSignal object)
    removed (a boolean for bookkeeping purposes, initially false) 
}

现在,该列表中有很多有用的属性,但为了删除事件侦听器,这signal是我们想要使用的属性(在 2020 年末添加到 DOM 级别 3 中),因为它让我们知道JS 引擎只需调用即可删除事件侦听器,abort()而不必费心removeEventListener

const areaListener = (new AbortController()).signal;

area.addEventListener(
  `click`,
  function(event) {
    app.addSpot(event.clientX, event.clientY);
    app.addFlag = 1;
  },
  { signal: areaListener }
);

(注意这里没有使用useCapture标志,因为useCapture标志本质上是完全没用的)

现在,当需要删除该事件侦听器时,我们只需运行:

areaListener.abort()

完成:JS 引擎将中止并清理我们的事件监听器。不保留对处理函数的引用,不确保我们调用的属性与调用removeEventListener的属性完全相同addEventListener:我们只是取消侦听器。

于 2021-12-27T17:21:36.647 回答
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 ); 
       } 
}
于 2021-02-14T13:01:30.743 回答
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] 将点击事件处理程序附加到 Button #1;

[2] 测试我点击按钮时是否调用了事件处理程序;

[3] 一旦测试通过,点击 Button #2,并调用附加到其上的事件处理程序,这将删除附加到 Button #1 的旧事件处理程序,然后用新的事件处理程序替换它。

步骤 [1] 和 [2] 工作正常。事件处理程序已附加,并在我单击按钮时调用。

问题在于步骤 [3]。

即使我保存了对 MakeEventHandler() 生成的函数的引用,特别是为了在步骤 [3] 中删除该事件侦听器,对 removeEventListener() 的调用也不会删除事件侦听器。随后单击按钮 #1 会触发两个事件侦听器,包括我应该删除的那个!

不用说,尽管仔细设置了所有内容,以便我在 removeEventListener() 调用中指定的函数与我最初使用 addEventListener() 添加的函数相同,但我还是觉得这种行为令人费解——根据我关于该主题的所有文档'已经阅读(包括这个线程),为每个调用传递对相同函数的引用应该可以工作,但显然不行。

在步骤 [1] 中,控制台中的测试输出按预期读取:

按钮 1 初始事件处理程序已触发

正如预期的那样,代码也在步骤 [2] 中运行,并且对代码的逐步跟踪表明,确实,代码按预期执行。

但是在步骤 [3] 中,虽然第一次单击按钮 #1 会产生所需的结果:

按钮 1 最终事件处理程序已触发

随后单击 Button #1 时发生的情况是:

触发按钮 1 初始事件处理程序 触发按钮 1 最终事件处理程序

当然,即使最初附加到 Button #1 的函数仍然存在于内存中,因为它是在闭包中生成的,它仍然应该从元素的事件侦听器集合中分离出来吗?为什么还连接着?

还是我遇到了一些奇怪的错误,涉及使用带有事件侦听器的闭包,需要报告?

于 2018-01-18T11:00:18.150 回答
0

我有一个数据分页系统,这个功能提供了很多信息来创建表和插入新的寄存器,所以,在任何导航中我必须在添加按钮上添加一个事件监听器,我发现最好的方法是销毁元素并在添加事件监听器之前再次创建,这对我来说很好

于 2021-04-23T03:19:54.183 回答