Javascript/DOM: как удалить все события объекта DOM?

Просто вопрос: есть ли способ полностью удалить все события объекта, например. div?

EDIT: я добавляю за 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);
}

Ответ 1

Я не уверен, что вы имеете в виду под удалением всех событий. Удалить все обработчики для определенного типа событий или все обработчики событий для одного типа?

Удалить все обработчики событий

Если вы хотите удалить все обработчики событий (любого типа), вы можете клонировать элемент и заменить его на клон:

var clone = element.cloneNode(true);

Примечание: Это сохранит атрибуты и дочерние элементы, но не сохранит никаких изменений в свойствах DOM.


Удалить "анонимные" обработчики событий определенного типа

Другой способ - использовать removeEventListener(), но я думаю, вы уже пробовали это, и это не сработало. Вот подвох:

Вызов addEventListener анонимной функции каждый раз создает нового слушателя. Вызов removeEventListener анонимной функции не имеет никакого эффекта. Анонимная функция создает уникальный объект каждый раз, когда она вызывается, она не является ссылкой на существующий объект, хотя она может вызывать его. При добавлении прослушивателя событий таким способом убедитесь, что он добавлен только один раз, он является постоянным (не может быть удален) до тех пор, пока объект, к которому он был добавлен, не будет уничтожен.

По сути, вы передаете анонимную функцию addEventListener, поскольку eventReturner возвращает функцию.

У вас есть две возможности решить эту проблему:

  1. Не используйте функцию, которая возвращает функцию. Используйте функцию напрямую:

    function handler() {
        dosomething();
    }
    
    div.addEventListener('click',handler,false);
    
  2. Создайте оболочку для addEventListener, которая хранит ссылку на возвращаемую функцию, и создайте странную функцию removeAllEvents:

    var _eventHandlers = {}; // somewhere global
    
    function addListener(node, event, handler, capture) {
        if(!(node in _eventHandlers)) {
            // _eventHandlers stores references to nodes
            _eventHandlers[node] = {};
        }
        if(!(event in _eventHandlers[node])) {
            // each entry contains another entry for each event type
            _eventHandlers[node][event] = [];
        }
        // capture reference
        _eventHandlers[node][event].push([handler, capture]);
        node.addEventListener(event, handler, capture);
     }
    
    function removeAllListeners(node, event) {
        if(node in _eventHandlers) {
            var handlers = _eventHandlers[node];
            if(event in handlers) {
                var eventHandlers = handlers[event];
                for(var i = eventHandlers.length; i--;) {
                    var handler = eventHandlers[i];
                    node.removeEventListener(event, handler[0], handler[1]);
                }
            }
        }
    }
    

    И тогда вы можете использовать его с:

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

DEMO

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

Ответ 2

Используйте собственную функцию прослушивателя событий remove(). Например:

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

Ответ 3

Это приведет к удалению всех слушателей от детей, но будет медленным для больших страниц. Жестко просто писать.

element.outerHTML = element.outerHTML;

Ответ 4

Как утверждает corwin.amber, существуют различия между 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) }
  ) 
}

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

Наслаждайтесь!

Ответ 5

Может быть, браузер сделает это за вас, если вы сделаете что-то вроде:

Скопируйте div и его атрибуты и вставьте его перед старым, затем переместите содержимое из старого в новое и удалите старый?

Ответ 6

Только хром

Поскольку я пытаюсь удалить EventListener в тесте Protractor и не имею доступа к прослушивателю в тесте, следующее работает для удаления всех прослушивателей событий одного типа:

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

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

Ответ 7

Чтобы завершить ответы, вот реальные примеры удаления событий, когда вы посещаете веб-сайты и не можете контролировать сгенерированный код HTML и JavaScript.

Некоторые раздражающие веб-сайты не позволяют копировать и вставлять имена пользователей в формы входа в систему, что может быть легко onpaste если событие onpaste было добавлено с HTML-атрибутом onpaste="return false". В этом случае нам просто нужно щелкнуть правой кнопкой мыши на поле ввода, выбрать "Проверить элемент" в браузере, таком как Firefox, и удалить атрибут HTML.

Однако, если событие было добавлено через JavaScript, как это:

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

Мы также должны удалить событие через JavaScript:

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

В моем примере я использовал идентификатор "lyca_login_mobile_no", поскольку это был идентификатор ввода текста, используемый веб-сайтом, который я посещал.

Другой способ удалить событие (которое также удалит все события) - это удалить узел и создать новый, как мы должны сделать, если 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);

Обновление: если веб-приложение создано с использованием JavaScript-инфраструктуры, такой как Angular, похоже, что предыдущие решения не работают или не нарушают работу приложения. Другой способ разрешить вставку - установить значение через JavaScript:

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

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

Ответ 8

Вы можете добавить другого прослушивателя событий и вызвать preventDefault(), чтобы остановить распространение предыдущих прослушивателей.

document.querySelectorAll('a.my-link').forEach((el) => {
  el.addEventListener('click', (ev) => {
    ev.preventDefault()
  })
})

Ответ 9

Одним из методов является добавление нового прослушивателя событий, который вызывает e.stopImmediatePropagation().

Ответ 10

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

подробнее подробности

Ответ 11

Удаление всех событий на 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()
  })   
}