Javascript / DOM: Bir DOM nesnesinin tüm olayları nasıl kaldırılır?


97

Sadece soru: Bir nesnenin tüm olaylarını, örneğin bir div'i tamamen kaldırmanın bir yolu var mı?

DÜZENLEME: div.addEventListener('click',eventReturner(),false);Bir olay için ekliyorum .

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

DÜZENLEME2: Çalışan, ancak durumum için kullanmam mümkün olmayan bir yol buldum:

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);
}

Olayları nasıl iliştiriyorsunuz?
Felix Kling

2
Başlık nesnenin unsurlarını sorarken asıl soru olayları sorar . Alt öğeleri veya olayları kaldırmak istiyor musunuz?
Pär Wieslander

oh d * mn, çünkü bunu yazdığımda başka bir şey düşünüyordum ... olayları
Florian Müller

Durumun tam olarak ne olduğunu bilmiyorum, ancak bazı durumlarda geçici bir çözüm olarak, her zaman tek bir dinleyici ile çalışan ve div.onclick=null. Elbette addEventListenerbu durumda tamamen kullanmamalısınız çünkü bu durum, içindeki olandan farklı bir dinleyici katacaktır onclick.
venimus

Yanıtlar:


106

Tüm olayları kaldırmakla ne demek istediğinizden emin değilim . Belirli bir olay türü için tüm işleyicileri veya bir tür için tüm olay işleyicileri kaldırılsın mı?

Tüm olay işleyicilerini kaldır

Tüm olay işleyicilerini (herhangi bir türden) kaldırmak isterseniz , öğeyi klonlayabilir ve klonuyla değiştirebilirsiniz:

var clone = element.cloneNode(true);

Not: Bu, öznitelikleri ve alt öğeleri korur, ancak DOM özelliklerinde yapılan herhangi bir değişikliği korumaz.


Belirli türdeki "anonim" olay işleyicilerini kaldırın

Diğer yol kullanmak removeEventListener()ama sanırım bunu zaten denedin ve işe yaramadı. İşte yakalama :

addEventListenerAnonim bir işlevi çağırmak , her seferinde yeni bir dinleyici oluşturur. Arayan removeEventListenerisimsiz bir işleve hiçbir etkisi yoktur . Anonim bir işlev, her çağrıldığında benzersiz bir nesne yaratır, var olan bir nesneyi çağırsa da bu, mevcut bir nesneye referans değildir. Bu şekilde bir olay dinleyicisi eklerken, yalnızca bir kez eklendiğinden emin olun, eklendiği nesne yok edilene kadar kalıcıdır (kaldırılamaz).

Esasen anonim bir işlevi bir işlev döndürür addEventListenerolarak eventReturneriletiyorsunuz.

Bunu çözmek için iki seçeneğiniz var:

  1. Bir işlev döndüren bir işlev kullanmayın. İşlevi doğrudan kullanın:

    function handler() {
        dosomething();
    }
    
    div.addEventListener('click',handler,false);
    
  2. Bunun addEventListeneriçin döndürülen işleve bir başvuru depolayan bir sarmalayıcı oluşturun ve bazı garip removeAllEventsişlevler oluşturun:

    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,
      )
    }
    

    Ve sonra şununla kullanabilirsiniz:

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

DEMO

Not: Kodunuz uzun süre çalışıyorsa ve çok sayıda öğe oluşturuyor ve kaldırıyorsanız, _eventHandlersonları yok ettiğinizde içerdiği öğeleri kaldırdığınızdan emin olmanız gerekir.


@Florian: Kesinlikle, kod geliştirilebilir, ancak size bir fikir vermeli ... mutlu kodlama!
Felix Kling

2
Bunu birden fazla div öğesi ile denediniz mi? düğüm değişkeni aslında bir dizeye dönüştürülür, örneğin '[object HTMLDivElement]', bu da her şeyi aynı düğüme ekleyeceğiniz anlamına gelir.
cstruter

@cstruter: Doğru ... JavaScript'in ilk günlerindeydi ... Biraz daha zaman bulduğumda kodu düzelteceğim. Bilmeme izin verdiğin için teşekkürler.
Felix Kling

Sanırım bir yazım hatası var,
addListener

element.parentNodeBoş olabileceğini unutmayın . Muhtemelen yukarıdaki kod parçasının etrafını kontrol etmelisiniz.
thecoolmacdude

43

Bu, tüm dinleyicileri çocuklardan kaldıracak ancak büyük sayfalarda yavaş olacaktır. Yazması acımasızca basit.

element.outerHTML = element.outerHTML;

2
Mükemmel cevap. Yaprak düğümleri için bu en iyi fikir gibi görünüyor.
user3055938

3
document.querySelector('body').outerHTML = document.querySelector('body').outerHTMLbenim için çalıştı.
Ryan

2
@Ryan yerine document.querySelector('body').outerHTMLyazabilirsinizdocument.body.outerHTML
Jay Dadhania

28

Olay dinleyicisinin kendi işlevini kullanın remove(). Örneğin:

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

2
Bunun neden doğru cevap olmadığından emin değilim. Soru SO'da pek çok kez görünür ve cevaplar klon yöntemini kullanarak sorunu çözebilir.
jimasun

42
Görünüşe göre getEventListenersbu yalnızca WebKit geliştirme araçlarında ve FireBug'da mevcut. Sadece kodunuzda arayabileceğiniz bir şey değil.
corwin.amber

1
bunu çalıştırmakta zorlandıysanız, bir nesneyi argüman olarak iletirsiniz getEventListeners(). örnek: getEventListeners(document)veyagetEventListeners(document.querySelector('.someclass'))
Luke

10
Bu sadece krom konsolda çalışıyor gibi görünüyor . Sayfadaki senaryonuzda bile çalışmıyor.
Reuel Ribeiro

4
getEventListeners(document).click.forEach((e)=>{e.remove()})şu hatayı üretir:VM214:1 Uncaught TypeError: e.remove is not a function
Ryan

11

Corwin.amber'in dediği gibi, Webkit ile diğerleri arasında farklılıklar vardır.

Chrome'da:

getEventListeners(document);

Bu size mevcut tüm olay dinleyicileriyle bir Nesne verir:

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

Buradan kaldırmak istediğiniz dinleyiciye ulaşabilirsiniz:

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

Yani tüm olay dinleyicileri:

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

Firefox'ta

Biraz farklıdır, çünkü kaldırma işlevi içermeyen bir dinleyici sarmalayıcı kullanır. Kaldırmak istediğiniz dinleyiciyi almalısınız:

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

Tüm olay dinleyicileri:

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

Bir haber sitesinin sinir bozucu kopya korumasını devre dışı bırakmaya çalışırken bu gönderiye rastladım.

Zevk almak!


Bu, tüm dinleyicilerini kaldırmadan belge düğümündeki belirli bir dinleyicinin kaldırılması durumunda olduğu gibi, dinleyicilerin kaldırılmasını hedeflemek için en iyi yanıttır.
Trevor

Bu iyi çalışıyor ve en iyi cevap. @Jmakuc Çok teşekkürler.
Thavamani Kasi

5
Firefox bana bunun getEventListenerstanımlanmadığını mı söylüyor ?
rovyko

Bu kötü bir çözümdür çünkü şu anda getEventListeners yalnızca Chrome tarafından desteklenmektedir.
Michael Paccione

1

Tüm aramaları kesmek için bir kanca işlevi ekleyebilirsiniz addEventHandler. Kanca, işleyiciyi temizlik için kullanılabilecek bir listeye iter. Örneğin,

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;
}

Bu kodu ana web sayfanızın üst kısmına yakın bir yere eklemelisiniz (örneğin index.html). Temizleme sırasında, tüm işleyiciler arasında döngü oluşturabilir ve her biri için removeEventHandler'ı çağırabilirsiniz. RemoveEventHandler'ı aynı işlevle birden çok kez çağırma konusunda endişelenmeyin. Zararsızdır.

Örneğin,

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);
    } 
}

Not: IE için EventTarget yerine Element kullanın ve => işlevini değiştirin ve diğer çeşitli şeyler.


0

Yanıtları tamamlamak için, burada web sitelerini ziyaret ettiğinizde ve oluşturulan HTML ve JavaScript kodu üzerinde kontrolünüz olmadığında olayları kaldırmanın gerçek dünyadan örnekleri verilmiştir.

Bazı sinir bozucu web siteleri, oturum açma formlarına kullanıcı adlarını kopyalayıp yapıştırmanızı engelliyor; bu, onpasteetkinlik onpaste="return false"HTML özelliğiyle eklenirse kolayca atlanabilir . Bu durumda, giriş alanına sağ tıklamamız, Firefox gibi bir tarayıcıda "Öğeyi incele" yi seçmemiz ve HTML özelliğini kaldırmamız gerekir.

Ancak, etkinlik şu şekilde JavaScript aracılığıyla eklenmişse:

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

Etkinliği JavaScript aracılığıyla da kaldırmamız gerekecek:

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

Örneğimde, ziyaret ettiğim web sitesi tarafından kullanılan metin giriş kimliği olduğu için "lyca_login_mobile_no" kimliğini kullandım.

Olayı kaldırmanın başka bir yolu (tüm olayları da kaldırır), düğümü kaldırmak ve yeni bir tane oluşturmaktır, tıpkı addEventListenerkaldıramayacağımız anonim bir işlevi kullanarak olaylar eklemek için kullanılmışsa yapmamız gerektiği gibi removeEventListener. Bu, tarayıcı konsolu aracılığıyla bir öğeyi inceleyerek, HTML kodunu kopyalayarak, HTML kodunu kaldırarak ve ardından HTML kodunu aynı yere yapıştırarak da yapılabilir.

JavaScript aracılığıyla daha hızlı ve otomatik olarak da yapılabilir:

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

Güncelleme: Web uygulaması, Angular gibi bir JavaScript çerçevesi kullanılarak yapılmışsa, önceki çözümlerin çalışmadığı veya uygulamayı bozmadığı görülür. Yapıştırmaya izin vermek için başka bir geçici çözüm, değeri JavaScript aracılığıyla ayarlamak olabilir:

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

Şu anda, Angular gibi tamamen JavaScript ile yazılmış bir uygulamayı bozmadan tüm form doğrulama ve kısıtlama olaylarını kaldırmanın bir yolu olup olmadığını bilmiyorum.


0

açısal bir polyfill var bu sorun için kontrol edebilirsiniz. Pek anlamadım ama belki yardımcı olabilir.

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;
        }
    };

....


Nereden EVENT_NAME_SYMBOL_REGXgelmeli?
Elias Zamaria

0

Örneğin olay dinleyicisini temizleyen bir yardımcı işlev ekleyebilirsiniz.

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

sadece öğeyi işleve aktarın ve işte bu kadar ...


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

//Düzenle

Etkinlik eklemek için hangi yöntemi kullandığınızı bilmiyordum. Bunu addEventListenerkullanabilirsiniz:

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

daha fazla detay


1
ben gibi kümesi ise div.onClick = somethingo zaman ben önceki üzerindeki ve örnek null bir nedenle ... başka olay onClick, ama önceki kalır setleri
Florian Müller

1
İşleyiciler aracılığıyla eklenirse çalışmaz addEventListener().
Felix Kling

@Florian: Hayır, bu doğru değil. Bu olay işleyicisi ekleme yöntemini kullanırsanız, bir olay için yalnızca bir işleyiciniz olabilir . Ama şunu kullanırsanız bir fark yaratır addEventListener()...
Felix Kling

ama bunu böyle gördüm, bu yüzden önceki işlevi tekrar eklersem, iki kez çağrılacak ... ve Felix King'in dediği gibi, bu addEventListener ile çalışmıyor ...
Florian Müller

-1

Aşağıdakiler gibi bir şey yaparsanız tarayıcı sizin için yapacak olabilir:

divVe özniteliklerini kopyalayın ve eskisinin önüne ekleyin, ardından içeriği eskiden yeniye taşıyın ve eskisini silin.


şimdi bu aslında iyi bir fikir, ama tamamen yetersiz, eğer bunu 1'000 ile 1'000'000 arasındaki bir çok div için yapmanız gerekiyorsa ... Evet, bu büyük bir proje;)
Florian Müller

6
Bir sayfada 1 milyon div var mı? Bundan önce başka sorunlara da gireceksiniz;) Etkinlik delegasyonu kullanılabilir sonra ...
Mic

-1

Şuradaki tüm olayların kaldırılmasıdocument :

Tek astar:

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

Güzel versiyon:

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

-1

Yalnızca Chrome

Bir İletki testindeki bir EventListener'ı kaldırmaya çalıştığım ve testte Dinleyiciye erişimim olmadığından, aşağıdakiler tek bir türdeki tüm olay dinleyicilerini kaldırmak için çalışır:

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

Umarım bu, bir önceki yanıtın o zamandan beri artık çalışmayan "kaldır" yöntemini kullanmasına yardımcı olur.


-1

Bir yöntem, e.stopImmediatePropagation () öğesini çağıran yeni bir olay dinleyicisi eklemektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.