重新绑定JavaScript事件和addEventListener两次

时间:2017-01-18 13:39:17

标签: javascript javascript-events

我有一个定义事件监听器的类方法。为简单起见,我们使用以下代码段。



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>
&#13;
&#13;
&#13;

仅使用bindEvents()一次时一切正常,但是例如在ajax回调中再次调用它会导致侦听器执行两次。所以这意味着在第二个bindEvents()之后,单击按钮将console.log()两次,依此类推。有没有办法解决这种问题?

我知道我可以动态绑定事件&#34;动态&#34;在文档上并查看e.target,但有一种情况我需要mouseenter / mouseleave事件,我不认为总是在文档上有这些eventListener是个好主意。

我已经阅读了以下某处,但似乎是错误的......

  

.addEventListener方法确保相同的函数引用   不会被多次绑定到相同的元素/事件/捕获   组合

此外,我还使用https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener中的options参数,但没有成功。

对不起,如果在某个地方得到了解答,但我没能在SO和搜索引擎中找到答案。

更新:有没有办法覆盖现有的eventListeners,旧的应该删除removeEventListener,如下面建议的 kcp ?对这个问题有更优雅的解决方案吗?

3 个答案:

答案 0 :(得分:3)

  

.addEventListener方法确保相同的函数引用不会多次绑定到相同的元素/事件/捕获组合。

在您的情况下,每次执行bindEvents()时,都会将全新的处理程序传递给click事件侦听器,因为您定义了新函数(无论它看起来是否相同,它都是不同的对象)。要在每次必须在bindEvents之外定义它并使用名称(通过引用)传递时使用相同的处理程序。这有效:

&#13;
&#13;
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();
&#13;
<button>click</button>
&#13;
&#13;
&#13;

但是使用jQuery我使用以下方法,它允许我指定只绑定特定容器(context或ctx)中的元素:

&#13;
&#13;
$.fn.bindEvents = function bindEvents(ctx){

	ctx = ctx || this;

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

$('body').bindEvents();

$('div').bindEvents();
&#13;
<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>
&#13;
&#13;
&#13;

在上面的示例中,bindEvents执行了两次,但第一个按钮只绑定了一次,因为它不在div中。如果你点击第二个按钮,它会提醒两次因为满足两个上下文。

答案 1 :(得分: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

答案 2 :(得分: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>