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

これは、2つの無名関数が完全に異なる関数であるためです。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

両方の呼び出しで2つの異なる関数を作成しています。したがって、2番目の関数は最初の関数とはまったく関係がなく、エンジンは関数を削除できます。代わりに、関数に共通の識別子を使用してください。

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

イベントリスナーによって呼び出された関数にローカル変数を渡したい場合は、関数内で関数を定義し(ローカル変数を取得するため)、関数自体で関数の名前を渡すことができます。たとえば、ローカル変数としてアプリを使用してイベントリスナーを追加する関数の内部から始めましょう。この関数内に、次のような関数を記述します。

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

説明が必要なremoveEventListener()で問題が発生しました。

イベントリスナーにパラメーターを渡せるようにしたかったので、イベントリスナーを生成する関数を作成しました。この関数は、目的のイベントリスナーをコールバックとして呼び出す2番目の関数を返します。

完全なライブラリファイルは次のとおりです。

//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]クリックイベントハンドラーをボタン#1にアタッチします。

[2]ボタンをクリックしたときにイベントハンドラーが呼び出されるかどうかをテストします。

[3]そのテストに合格したら、ボタン#2をクリックし、それに接続されているイベントハンドラーを呼び出します。これにより、ボタン#1に接続されている古いイベントハンドラーが削除され、新しいイベントハンドラーに置き換えられます。

手順[1]と[2]は正常に機能します。イベントハンドラーがアタッチされており、ボタンをクリックするたびに呼び出されます。

問題はステップ[3]にあります。

特にステップ[3]でそのイベントリスナーを削除する目的で、MakeEventHandler()によって生成された関数への参照を保存しましたが、removeEventListener()を呼び出してもイベントリスナーは削除されません。続いてボタン#1をクリックすると、削除したと思われるものを含め、両方のイベントリスナーが起動します。

言うまでもなく、removeEventListener()の呼び出しで指定する関数が、addEventListener()で最初に追加した関数と同じになるようにすべてを注意深く設定しているにもかかわらず、この動作は不可解です。 (このスレッドを含めて)読んだことがあるので、呼び出しごとに同じ関数への参照を渡すことは機能するはずですが、明らかに機能しません。

ステップ[1]で、コンソールのテスト出力は期待どおりに読み取られます。

ボタン1の初期イベントハンドラーがトリガーされました

コードも期待どおりにステップ[2]で実行され、コードのステップバイステップのトレースにより、実際にコードが期待どおりに実行されていることがわかります。

ただし、ステップ[3]では、ボタン#1を最初にクリックすると、目的の結果が得られます。

ボタン1の最終イベントハンドラーがトリガーされました

続いてボタン#1をクリックすると、次のようになります。

ボタン1の初期イベントハンドラーがトリガーされましたボタン1の最終イベントハンドラーがトリガーされました

確かに、ボタン#1に最初にアタッチされた関数がまだメモリに残っている場合でも、クロージャー内で生成されたため、要素のイベントリスナーコレクションからデタッチする必要がありますか?なぜまだ接続されているのですか?

または、イベントリスナーでクロージャを使用することに関する奇妙なバグに遭遇しましたが、それを報告する必要がありますか?

于 2018-01-18T11:00:18.150 に答える
0

これは私がやったことですが、ルートクラスにありますが、あまり違いはありません。Model()が呼び出されるたびにイベントリスナーが蓄積されないようにするだけでなく、モデルが毎回変更されるように引数とスコープも必要でした。 。

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

私はデータのページ付けを備えたシステムを持っています、この関数はテーブルを作成して新しいレジスタを挿入する多くの情報を提供します、それでどんなナビゲーションでも私は追加ボタンでイベントリスナーを追加しなければなりません、私が見つけた最良の方法は要素を破壊してイベントリスナーを追加する前にもう一度作成することです、これは私にはうまくいきました

于 2021-04-23T03:19:54.183 に答える
0

react jsの機能コンポーネントでイベントリスナーを削除する問題に直面している場合は、再レンダリングのたびに関数参照getの変更が発生します。削除しようとすると、参照参照が既に変更されているため、そのイベントリスナーを削除できません。関数コンポーネントが複数回再レンダリングされる場合でも、reactprovideフックを使用して関数の参照を保持します。イベントリスナーのコールバック関数をuseCallbackフックでラップすると、関数が複数回再レンダリングされても、その参照は同じままです。

const function = useCallback((e) => {

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

を使用せずにイベントリスナーを削除するメカニズムを提供するJavaScript仕様の一部をカバーしている人はいないようですremoveEventListenerhttps://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

配列に関数ストアを追加し、パスバイマップを削除している間

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 に答える