Javascript / DOM:DOMオブジェクトのすべてのイベントを削除する方法は?


97

質問:divなどのオブジェクトのすべてのイベントを完全に削除する方法はありますか?

編集:私はdiv.addEventListener('click',eventReturner(),false);イベントごとに追加しています。

function eventReturner() {
    return function() {
        dosomething();
    };
}

EDIT2:動作している方法を見つけましたが、私の場合は使用できません:

var returnedFunction;
function addit() {
    var div = document.getElementById('div');
    returnedFunction = eventReturner();
    div.addEventListener('click',returnedFunction,false); //You HAVE to take here a var and not the direct call to eventReturner(), because the function address must be the same, and it would change, if the function was called again.
}
function removeit() {
    var div = document.getElementById('div');
    div.removeEventListener('click',returnedFunction,false);
}

イベントをどのように添付しますか?
Felix Kling 2010

2
タイトルはオブジェクトの要素について尋ねますが、実際の質問はイベントについて尋ねます。子要素またはイベントを削除しますか?
パーWieslander

ああd * mn、それは私がそれを書いたときに私が何か他のことを考えていた原因でした...私はイベントを
フロリアンミュラー2010

正確なケースはわかりませんが、回避策として「on *」メソッド(div.onclick = functionとして)を使用できます。これは常に単一のリスナーで機能し、として簡単に削除できdiv.onclick=nullます。もちろんaddEventListener、この場合は、のリスナーとは異なる別のリスナーを追加するため、まったく使用しないでくださいonclick
venimus 2017年

回答:


105

すべてのイベント削除するとはどういう意味かわかりません。特定のタイプのイベントのすべてのハンドラーを削除しますか、それとも1つのタイプのすべてのイベントハンドラーを削除しますか?

すべてのイベントハンドラーを削除します

(任意のタイプの)すべてのイベントハンドラーを削除する場合は、要素のクローンを作成して、そのクローンに置き換えることができます。

var clone = element.cloneNode(true);

注:これにより、属性と子は保持されますが、DOMプロパティへの変更は保持されません。


特定のタイプの「匿名」イベントハンドラーを削除する

別の方法は使用するremoveEventListener()ことですが、あなたはすでにこれを試したと思いますが、うまくいきませんでした。これがキャッチです:

addEventListener匿名関数を呼び出すと、毎回新しいリスナーが作成されます。removeEventListener匿名関数を呼び出しても効果はありません。匿名関数は、呼び出されるたびに一意のオブジェクトを作成します。既存のオブジェクトを呼び出すことはできますが、それを参照することはできません。この方法でイベントリスナーを追加するときは、一度だけ追加するようにしてください。追加されたオブジェクトが破棄されるまで、永続的です(削除できません)。

基本的に無名関数をaddEventListenerasに渡して、関数をeventReturner返します。

これを解決するには、2つの可能性があります。

  1. 関数を返す関数は使用しないでください。関数を直接使用します。

    function handler() {
        dosomething();
    }
    
    div.addEventListener('click',handler,false);
    
  2. addEventListener返された関数への参照を格納するラッパーを作成し、奇妙なremoveAllEvents関数を作成します。

    var _eventHandlers = {}; // somewhere global
    
    const addListener = (node, event, handler, capture = false) => {
      if (!(event in _eventHandlers)) {
        _eventHandlers[event] = []
      }
      // here we track the events and their nodes (note that we cannot
      // use node as Object keys, as they'd get coerced into a string
      _eventHandlers[event].push({ node: node, handler: handler, capture: capture })
      node.addEventListener(event, handler, capture)
    }
    
    const removeAllListeners = (targetNode, event) => {
      // remove listeners from the matching nodes
      _eventHandlers[event]
        .filter(({ node }) => node === targetNode)
        .forEach(({ node, handler, capture }) => node.removeEventListener(event, handler, capture))
    
      // update _eventHandlers global
      _eventHandlers[event] = _eventHandlers[event].filter(
        ({ node }) => node !== targetNode,
      )
    }
    

    そして、あなたはそれを一緒に使うことができます:

    addListener(div, 'click', eventReturner(), false)
    // and later
    removeAllListeners(div, 'click')
    

デモ

注:コードが長時間実行され、多くの要素を作成および削除する場合は、_eventHandlersそれらを破棄するときに、含まれている要素を必ず削除する必要があります。


@Florian:確かに、コードは改善される可能性がありますが、それはあなたにアイデアを与えるはずです...幸せなコーディング!
Felix Kling 2010

2
複数のdiv要素でこれを試しましたか?ノード変数は実際には文字列に変換されます。たとえば、「[object HTMLDivElement]」は、すべてを同じノードに追加することを意味します。
cstruter 2012

@cstruter:そうです...これはJavaScriptの初期の頃でした...もう少し時間があればコードを修正します。知らせてくれてありがとうございます。
Felix Kling 2012

タイプミスがあると思います。addListenerはaddEventである必要があります
AGamePlayer 2016年

element.parentNodenullになる可能性があることに注意してください。上記のコードの周りにifチェックを入れる必要があります。
thecoolmacdude 2017

42

これにより、子からすべてのリスナーが削除されますが、大きなページでは遅くなります。残酷に書くのは簡単です。

element.outerHTML = element.outerHTML;

2
素晴らしい答え。リーフノードの場合、これが最良のアイデアのようです。
user3055938 2017年

3
document.querySelector('body').outerHTML = document.querySelector('body').outerHTML私のために働いた。
ライアン

2
あなたの代わりに@Ryanはただdocument.querySelector('body').outerHTMLタイプすることができますdocument.body.outerHTML
Jay Dadhania

28

イベントリスナー独自の関数を使用しますremove()。例えば:

getEventListeners().click.forEach((e)=>{e.remove()})

2
これが正しい答えではない理由がわかりません。質問はSOに何度も表示され、クローンメソッドを使用して問題を処理する回答が得られる場合があります。
jimasun 2016年

42
そのようであるgetEventListenersWebKitの開発ツールにと放火魔でのみ使用可能です。コードで呼び出すことができるものではありません。
corwin.amber 2016

1
これを機能させるのに問題があった場合は、オブジェクトを引数としてに渡しますgetEventListeners()。例:getEventListeners(document)またはgetEventListeners(document.querySelector('.someclass'))
ルーク

10
これはChromeコンソールでのみ機能するようです。ページ上のスクリプトでも機能しません。
Reuel Ribeiro

4
getEventListeners(document).click.forEach((e)=>{e.remove()})このエラーが発生します:VM214:1 Uncaught TypeError: e.remove is not a function
ライアン

11

corwin.amberが言うように、Webkitと他のWebkitの間には違いがあります。

Chromeの場合:

getEventListeners(document);

これにより、既存のすべてのイベントリスナーを含むオブジェクトが得られます。

Object 
 click: Array[1]
 closePopups: Array[1]
 keyup: Array[1]
 mouseout: Array[1]
 mouseover: Array[1]
 ...

ここから、削除するリスナーにアクセスできます。

getEventListeners(document).copy[0].remove();

したがって、すべてのイベントリスナー:

for(var eventType in getEventListeners(document)) {
   getEventListeners(document)[eventType].forEach(
      function(o) { o.remove(); }
   ) 
}

Firefoxの場合

削除関数を含まないリスナーラッパーを使用しているため、少し異なります。削除するリスナーを取得する必要があります。

document.removeEventListener("copy", getEventListeners(document).copy[0].listener)

すべてのイベントリスナー:

for(var eventType in getEventListeners(document)) {
  getEventListeners(document)[eventType].forEach(
    function(o) { document.removeEventListener(eventType, o.listener) }
  ) 
}

私はニュースウェブサイトの迷惑なコピー防止を無効にしようとしているこの投稿に出くわしました。

楽しい!


これは、すべてのリスナーを削除せずにドキュメントノード上の特定のリスナーを削除する場合など、リスナーの削除をターゲットにするための最良の回答です。
トレバー

これはうまく機能し、ベストアンサーです。@Jmakucどうもありがとうございました。
Thavamani Kasi 2018

5
Firefoxは、getEventListeners定義されていないことを教えてくれますか?
rovyko

現在getEventListenersはChromeでのみサポートされているため、これは不十分なソリューションです。
Michael Paccione

1

へのすべての呼び出しをインターセプトするフック関数を追加できますaddEventHandler。フックは、クリーンアップに使用できるリストにハンドラーをプッシュします。例えば、

if (EventTarget.prototype.original_addEventListener == null) {
    EventTarget.prototype.original_addEventListener = EventTarget.prototype.addEventListener;

    function addEventListener_hook(typ, fn, opt) {
        console.log('--- add event listener',this.nodeName,typ);
        this.all_handlers = this.all_handlers || [];
        this.all_handlers.push({typ,fn,opt});
        this.original_addEventListener(typ, fn, opt);  
    }

    EventTarget.prototype.addEventListener = addEventListener_hook;
}

このコードは、メインのWebページの上部近くに挿入する必要があります(例index.html)。クリーンアップ中に、all_handlersをループして、それぞれに対してremoveEventHandlerを呼び出すことができます。同じ関数でremoveEventHandlerを複数回呼び出す必要はありません。無害です。

例えば、

function cleanup(elem) {
    for (let t in elem) if (t.startsWith('on') && elem[t] != null) {
        elem[t] = null;
        console.log('cleanup removed listener from '+elem.nodeName,t);
    } 
    for (let t of elem.all_handlers || []) {
        elem.removeEventListener(t.typ, t.fn, t.opt);
        console.log('cleanup removed listener from '+elem.nodeName,t.typ);
    } 
}

注: IEの場合、EventTargetの代わりにElementを使用し、=>を関数に変更するなどさまざまなことを行います。


0

答えを完成させるために、Webサイトにアクセスしていて、生成されたHTMLおよびJavaScriptコードを制御できない場合にイベントを削除する実際の例を次に示します。

一部の迷惑なWebサイトでは、ログインフォームにユーザー名をコピーして貼り付けることができません。これは、onpasteイベントがonpaste="return false"HTML属性で追加された場合に簡単にバイパスされる可能性があります。この場合、入力フィールドを右クリックし、Firefoxなどのブラウザで[要素の検査]を選択して、HTML属性を削除するだけです。

ただし、イベントが次のようにJavaScriptを介して追加された場合:

document.getElementById("lyca_login_mobile_no").onpaste = function(){return false};

JavaScriptを使用してイベントを削除する必要もあります。

document.getElementById("lyca_login_mobile_no").onpaste = null;

私の例では、ID「lyca_login_mobile_no」を使用しました。これは、アクセスしていたWebサイトで使用されているテキスト入力IDであるためです。

イベントを削除する別の方法(すべてのイベントも削除されます)は、ノードを削除して新しいノードを作成するaddEventListenerことremoveEventListenerです。これは、で削除できない無名関数を使用してイベントを追加するために使用された場合と同様です。これは、要素を検査し、HTMLコードをコピーし、HTMLコードを削除してから、同じ場所にHTMLコードを貼り付けることにより、ブラウザーコンソールから実行することもできます。

また、JavaScriptを使用して、より高速に自動化することもできます。

var oldNode = document.getElementById("lyca_login_mobile_no");
var newNode = oldNode.cloneNode(true);
oldNode.parentNode.insertBefore(newNode, oldNode);
oldNode.parentNode.removeChild(oldNode);

更新:WebアプリがAngularなどのJavaScriptフレームワークを使用して作成されている場合、以前のソリューションが機能していないか、アプリが壊れているように見えます。貼り付けを許可する別の回避策は、JavaScriptを使用して値を設定することです。

document.getElementById("lyca_login_mobile_no").value = "username";

現時点では、Angularのように完全にJavaScriptで記述されたアプリを壊さずに、すべてのフォーム検証イベントと制限イベントを削除する方法があるかどうかはわかりません。


0

Angularにはこの問題のポリフィルがあります。確認できます。私はあまり理解していませんでしたが、多分それは助けになるでしょう。

const REMOVE_ALL_LISTENERS_EVENT_LISTENER = 'removeAllListeners';

    proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () {
        const target = this || _global;
        const eventName = arguments[0];
        if (!eventName) {
            const keys = Object.keys(target);
            for (let i = 0; i < keys.length; i++) {
                const prop = keys[i];
                const match = EVENT_NAME_SYMBOL_REGX.exec(prop);
                let evtName = match && match[1];
                // in nodejs EventEmitter, removeListener event is
                // used for monitoring the removeListener call,
                // so just keep removeListener eventListener until
                // all other eventListeners are removed
                if (evtName && evtName !== 'removeListener') {
                    this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName);
                }
            }
            // remove removeListener listener finally
            this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener');
        }
        else {
            const symbolEventNames = zoneSymbolEventNames$1[eventName];
            if (symbolEventNames) {
                const symbolEventName = symbolEventNames[FALSE_STR];
                const symbolCaptureEventName = symbolEventNames[TRUE_STR];
                const tasks = target[symbolEventName];
                const captureTasks = target[symbolCaptureEventName];
                if (tasks) {
                    const removeTasks = tasks.slice();
                    for (let i = 0; i < removeTasks.length; i++) {
                        const task = removeTasks[i];
                        let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
                        this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
                    }
                }
                if (captureTasks) {
                    const removeTasks = captureTasks.slice();
                    for (let i = 0; i < removeTasks.length; i++) {
                        const task = removeTasks[i];
                        let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
                        this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
                    }
                }
            }
        }
        if (returnTarget) {
            return this;
        }
    };

...。


どこEVENT_NAME_SYMBOL_REGXから来るのですか?
エリアスザマリア

0

たとえば、イベントリスナーをクリアするヘルパー関数を追加できます

function clearEventListener(element) {
 const clonedElement = element.cloneNode(true);
element.replaceWith(clonedElement);
return clonedElement;
}

要素を関数に渡すだけで、それだけです...


-1
var div = getElementsByTagName('div')[0]; /* first div found; you can use getElementById for more specific element */
div.onclick = null; // OR:
div.onclick = function(){};

//編集

イベントの添付にどの方法を使用しているのかわかりませんでした。以下のためにaddEventListenerあなたはこれを使用することができます。

div.removeEventListener('click',functionName,false); // functionName is the name of your callback function

もっと 詳細


1
私は好きなように設定している場合div.onClick = something、私は以前と例のヌルのための1つの上に持っているので、それは...、別のイベントのonClickが、前回の滞在を設定します
フロリアン・ミュラー

1
ハンドラーがを介して追加された場合は機能しませんaddEventListener()
Felix Kling 2010

@Florian:いいえ、そうではありません。イベントハンドラーを追加するこの方法を使用する場合、イベントに対して持つことができるハンドラーは1つだけです。しかし、使用すると違いが生じますaddEventListener()...
Felix Kling 2010

私は再び以前の機能を追加した場合しかし、私はこれは...のaddEventListenerでは動作しません、フェリックス・キングが言うように、それは、二回と呼ばれる...となりますので、このようにそれを見てきました
フロリアン・ミュラー

-1

あなたが次のようなことをすれば、ブラウザがあなたのためにそれをするかもしれません:

divとその属性をコピーして古いものの前に挿入し、コンテンツを古いものから新しいものに移動して古いものを削除しますか?


あなたは1'000と1'000'000間のdivのamoundのためにこれをしなければならない場合は...はい、それは大きなプロジェクトですが、今、実際に良い考えであるが、完全にinperformant;)
フロリアン・ミュラー

6
1ページに100万のdiv?...)その後、使用イベント委任することができ、あなたはこの1の前に他のトラブルになります
マイク

-1

上のすべてのイベントを削除する document

一発ギャグ:

for (key in getEventListeners(document)) { getEventListeners(document)[key].forEach(function(c) { c.remove() }) }

きれいなバージョン:

for (key in getEventListeners(document)) {
  getEventListeners(document)[key].forEach(function(c) {
    c.remove()
  })   
}

-1

Chromeのみ

分度器テスト内でEventListenerを削除しようとしていて、テスト内のリスナーにアクセスできないため、次のように機能して、単一タイプのすべてのイベントリスナーを削除します。

function(eventType){
    getEventListeners(window).[eventType].forEach(
        function(e){
            window.removeEventListener(eventType, e.listener)
        }
    );
}

以前の回答が「削除」メソッドを使用していたため、これが誰かに役立つことを願っています。それ以降は機能しなくなります。


-1

1つの方法は、e.stopImmediatePropagation()を呼び出す新しいイベントリスナーを追加することです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.