Как удалить всех слушателей в элементе?

У меня есть кнопка, и я добавил к ней несколько eventlistners:

document.getElementById("btn").addEventListener("click", funcA, false);
document.getElementById("btn").addEventListener("click", funcB, false);
document.getElementById("btn").addEventListener("click", funcC, false);
document.getElementById("btn").addEventListener("blur" , funcD, false);
document.getElementById("btn").addEventListener("focus", funcE, false);

<button id="btn">button</button>

Я могу удалить их:

document.getElementById("btn").removeEventListener("click",funcA);

Что делать, если я хочу удалить всех слушателей сразу или у меня нет ссылки на функцию (funcA)? Есть ли способ сделать это, или мне придется удалять их по одному?


person Derek 朕會功夫    schedule 12.02.2012    source источник
comment
stackoverflow.com/questions/3222486/   -  person Misiur    schedule 12.02.2012
comment
Проголосовали за попытку грамотно кодировать, НЕ используя фреймворки / библиотеки. :-)   -  person John    schedule 13.02.2012
comment
@user Впечатляет, вы действительно нашли вопрос, который даже старше, чем этот старый вопрос, ответы на который все еще упоминают jQuery 1.7. Не могу поверить, сколько времени прошло с тех пор, как я задал этот вопрос.   -  person Derek 朕會功夫    schedule 09.01.2016


Ответы (3)


Я думаю, что самый быстрый способ сделать это - просто клонировать узел, который удалит все прослушиватели событий:

var old_element = document.getElementById("btn");
var new_element = old_element.cloneNode(true);
old_element.parentNode.replaceChild(new_element, old_element);

Просто будьте осторожны, так как это также очистит прослушиватели событий для всех дочерних элементов рассматриваемого узла, поэтому, если вы хотите сохранить это, вам придется прибегать к явному удалению прослушивателей по одному.

person Ben D    schedule 12.02.2012
comment
Спасибо! И я использовал ваш код вот так function unbind(ele){ele.parentNode.replaceChild(ele.cloneNode(true), ele);} - person Derek 朕會功夫; 12.02.2012
comment
@Derek: Клонировать узел и все поддерево - плохая идея. Это намного медленнее, чем удаление всех EventListener из узла с помощью node.removeEventListener. Вдобавок вы получите утечку памяти (узел + поддерево) и, конечно же, все EventListeners были удалены из поддерева. Если вы воспользуетесь своей функцией на document.body, вы все взорвете. - person Saxoier; 13.02.2012
comment
@Saxoier, Спасибо за напоминание, но я тестировал body на этой странице, и он отлично сработал. Может я использую быстрый браузер (Google Chrome). - person Derek 朕會功夫; 13.02.2012
comment
@Saxoier, безусловно, клонирование узла происходит медленнее, чем просто удаление слушателей, но в большинстве функциональных сценариев разница в скорости не будет заметна (если вы не делаете это с огромным количеством узлов страницы за один раз). Что касается утечки памяти, она будет зависеть от браузера ... Все современные браузеры должны обрабатывать сборку мусора достаточно хорошо, чтобы не возникло проблем (хотя, если узел содержит встроенные объекты, я могу представить себе сценарии, в которых это могло бы произойти). Вы имеете в виду конкретную задокументированную утечку памяти? - person Ben D; 13.02.2012
comment
@Saxoier, ваше замечание о влиянии клонирования на прослушиватели событий в поддереве узла заслуживает явного упоминания ... Я добавил предупреждение к своему ответу, так как люди должны знать об этом. - person Ben D; 13.02.2012
comment
@Ben D: Похоже, что в последних версиях Firefox, IE, Opera и Chrome есть достойный GC (сводка после 10 циклов ГХ). При определенных обстоятельствах старый IE будет протекать. - person Saxoier; 13.02.2012
comment
Можно ли клонировать узел без потери его слушателей? - person Shawn; 02.05.2012
comment
@Saxoier, из вашего комментария я понял, что клонирование - медленная и неэффективная операция. Но как насчет создания нового элемента (например, document.createElement('canvas'))? - person Ivan Kochurkin; 12.01.2013
comment
Для тех, кто ненавидит загадочные логические аргументы, cloneNode (true) означает клонирование узла, включая дочерние элементы. Документация: developer.mozilla.org/en-US/docs/ Веб / API / Node.cloneNode - person Andrew Dunkman; 24.07.2013
comment
Голос против ... интересно. - person Ben D; 26.07.2013
comment
@BenD интересно, есть 3 голоса против, но нет альтернативных ответов ... это довольно слабая оценка этих голосовавших против! - person AJP; 14.04.2014
comment
возможно, клонируйте узел без потомков, а затем переместите потомков. - person Eevee; 13.08.2014
comment
Что делать, если элемент является корневым html, у которого нет родительского элемента. - person Meow; 16.12.2017
comment
@Meow - у html действительно есть родитель: сам document. Я не уверен, что могу придумать случай, когда у вас были бы слушатели, прикрепленные к элементу html вместо body или оболочки, но теоретически это должно работать с узлом <html> (parentNode <html> - это просто document, поэтому логика работала бы). Однако я провел несколько тестов, и в некоторых браузерах, похоже, возникают проблемы с заменой узла document.html, поэтому на практике я бы избегал этого (хотя я бы также избегал добавления слушателей в html) - person Ben D; 31.12.2017
comment
По-видимому, он не удаляет обратные вызовы, добавленные с помощью html - person DarthCadeus; 15.12.2018
comment
может быть плохой идеей, но кажется единственным жизнеспособным вариантом - person stackers; 23.10.2020
comment
Конечно, это слишком ядерный вариант, если прослушиватель событий был зарегистрирован в объекте окна. - person Pangamma; 02.06.2021

Если вы используете события jquery, это можно сделать одной строкой:

Для событий jQuery (.on()):

$("#myEl").off()

Для собственных событий JavaScript (.addEventListener()):

$('#myEl').replaceWith($('#myEl').clone());

Вот пример:

http://jsfiddle.net/LkfLezgd/3/

person Duke    schedule 06.02.2015
comment
Это слишком долго, вместо этого в jQuery вы должны сделать это $("#myEl").unbind(); или .off() (1.7+), чтобы удалить всех слушателей. - person Derek 朕會功夫; 07.02.2015
comment
off() или unbind() удаляют только тех слушателей, подключенных через jQuery? - person davide; 26.02.2015
comment
Просто перечитайте документы по .off (), и это позволит вам опустить все параметры, чтобы удалить все привязки событий. Однако с .unbind () eventType является обязательным и поэтому непригоден для этой цели. - person Duke; 06.04.2015
comment
не знаю, почему эти unbind и off не работают. Однако $('#myEl').replaceWith($('#myEl').clone()); отлично работает! - person AGamePlayer; 13.01.2016
comment
@davide @Duke действительно off() и unbind() не будут работать для слушателей, зарегистрированных с помощью встроенного javascript addEventListener, согласно документации jquery. - person argaz; 26.10.2016
comment
Похоже, это удалит только события, созданные с помощью jQuery, поэтому это не полное решение. - person Nathan B; 05.06.2018
comment
Клон должен удалить все периоды прослушивателей событий. Подобно принятому ответу, только более читабельно. - person Duke; 21.09.2018
comment
Я ценю, что этот ответ начался с того, что если вы не против jquery - слишком много ответов просто используют jquery (иногда политика компании запрещает это). - person FinrodFelagund; 07.05.2020
comment
$ ('# myEl'). replaceWith ($ ('# myEl'). clone ()); Это сработало для меня, спасибо - person Javed Iqbal; 02.03.2021

Вот функция, которая также основана на cloneNode, но с возможностью клонирования только родительского узла и перемещения всех дочерних узлов (чтобы сохранить их прослушиватели событий):

function recreateNode(el, withChildren) {
  if (withChildren) {
    el.parentNode.replaceChild(el.cloneNode(true), el);
  }
  else {
    var newEl = el.cloneNode(false);
    while (el.hasChildNodes()) newEl.appendChild(el.firstChild);
    el.parentNode.replaceChild(newEl, el);
  }
}

Удалить прослушиватели событий для одного элемента:

recreateNode(document.getElementById("btn"));

Удалите прослушиватели событий для элемента и всех его дочерних элементов:

recreateNode(document.getElementById("list"), true);

Если вам нужно сохранить сам объект и поэтому вы не можете использовать cloneNode, вам нужно обернуть функцию addEventListener и самостоятельно отслеживать список слушателей, как в этот ответ.

person user    schedule 09.01.2016
comment
@Max: Я ценю ваше предложение по редактированию, но я считаю, что переделка этого кода в ES2015 не оправдана для этого случая, тогда код не получил бы широкой поддержки. - person user; 15.01.2016
comment
чтобы удалить все дочерние прослушивания, вы можете использовать: element.innerHTML + = ''; - person Nazar Vynnytskyi; 03.01.2017
comment
@NazarVynnytskyi действительно, это быстрое, но эффективное решение! - person Yes Barry; 23.03.2021