2017-01-18 3 views
0

У меня есть метод класса, который определяет прослушиватели событий. Для простоты воспользуемся следующим фрагментом кода.Повторить события JavaScript и addEventListener срабатывает дважды

function bindEvents() { 
 
    document.querySelector('button').addEventListener('click', (e) => { 
 
     console.log('clicked!'); 
 
    }); 
 
} 
 

 
// Initial event binding 
 
bindEvents(); 
 

 
// Rebind events at some point for dynamically created elements 
 
bindEvents();
<button type="button">Click</button>

Все отлично работает при использовании bindEvents() только один раз, однако, например, назвав его снова в Ajax результатов обратного вызова в слушателе, выполненных дважды. Таким образом, это означает, что после второго bindEvents() нажатие кнопки будет console.log() два раза и так далее. Есть ли способ, которым я могу обойти это поведение?

Я знаю, что я могу связать события «динамически» с документом и проверить с помощью e.target, но есть ситуация, когда мне нужны события mouseenter/mouseleave, и я не думаю, что это хорошая идея, чтобы всегда иметь эти eventListeners на документ.

Я где-то читал следующее, но мне кажется ложным ...

Метод .addEventListener обеспечивает те же функции, ссылка не будет связано более чем один раз на тот же элемент/события/захватывает комбинация.

Также я играл с параметром options отсюда https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener, но без успеха.

Извините, если на это был дан ответ, но я не смог найти ответ в SO и поисковых системах.

UPDATE: Есть ли способ, чтобы перезаписать существующие eventListeners или старые должны быть удалены с removeEventListener как ККТ предложил ниже? Есть ли более элегантное решение этой проблемы?

ответ

1

addEventListener не перезаписывает существующие прослушиватели событий, он просто добавляет новый, как следует из имени метода. Существующие слушатели должны быть удалены с использованием метода removeEventListener.

function onClick($event) { 
    console.log('clicked!'); 
} 
function bindEvents() { 
    /** Remove event listener first **/ 
    document.querySelector('button').removeEventListener('click', onClick); 
    document.querySelector('button').addEventListener('click', onClick); 
} 

removeEventListener docs

+0

Благодарим за предложение. Это, безусловно, будет работать, как вы думаете, может быть, есть более чистое решение проблемы? –

1

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

var elem = document.querySelector('div'); 
 

 
elem.addEventListener('click', function(e) { 
 
    e = e || event 
 
    var target = e.target; 
 
    if (target.nodeName != 'BUTTON') 
 
    return; 
 

 
    console.log('clicked ' + target.textContent); 
 
}); 
 

 
//Simulate addition of dynamic elements 
 
setTimeout(function() { 
 
    var newButton = document.createElement('button'); 
 
    newButton.innerHTML = 'Click 2'; 
 
    elem.appendChild(newButton) 
 
}, 2000)
<div> 
 
    <button type="button">Click</button> 
 
</div>

+0

Благодарим вас за предложение. Это, безусловно, будет работать. Однако, как я писал выше, могут быть события mousenter/mouseleave, и я не уверен, что это хорошая идея иметь этих слушателей в документе 24/7. Что вы думаете об этой «проблеме»? –

+0

@NikolayMihaylov, преимущество заключается в том, что подключен только один обработчик событий – Satpal

+0

@NikolayMihaylov и всегда присоединяем обработчик событий со статическим родительским элементом – Satpal

2

Метод .addEventListener гарантирует, что та же ссылка функция не будет связана более чем один раз к одному элементу/событие/захватывает комбинацию.

В вашем случае, каждый раз, когда вы выполняете bindEvents() совершенно новый обработчик передается слушателю click событий, так как вы определили новую функцию (независимо от того, она выглядит так же, то другой объект). Использовать один и тот же обработчик каждый раз, когда вы должны определить его за пределами bindEvents и передать его по имени (по ссылке).Это работает как expexted:

function clickHandler(e){ 
 
    alert('clicked!'); 
 
} 
 

 
function bindEvents() { 
 
    document.querySelector('button').addEventListener('click', clickHandler); 
 
} 
 

 
// Initial event binding 
 
bindEvents(); 
 

 
// Rebind events at some point for dynamically created elements 
 
bindEvents();
<button>click</button>

Однако с JQuery я использую следующий подход, который позволяет мне определить, что только элементы в специальный контейнер (контекст или СТХ) будут связаны:

$.fn.bindEvents = function bindEvents(ctx){ 
 

 
\t ctx = ctx || this; 
 

 
\t $('button', ctx).on('click', function(event){ 
 
\t \t alert(1); 
 
\t }); 
 
}; 
 

 
$('body').bindEvents(); 
 

 
$('div').bindEvents();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 

 
<button>Click</button> 
 

 
<div><button>in div </button></div>

В приведенном выше примере bindEvents выполняется дважды, но первая кнопка привязана только один раз, так как она не находится в div. Хотя, если вы нажмете на вторую кнопку, она дважды сообщит, потому что удовлетворяет оба контекста.

+0

Благодарим вас за предложение, сделаем некоторые тесты и вернемся с обратной связью. –

Смежные вопросы