删除重复的事件侦听器

Posted

技术标签:

【中文标题】删除重复的事件侦听器【英文标题】:Removing duplicate event listeners 【发布时间】:2018-01-25 03:59:13 【问题描述】:

我一直在尝试找到一种方法来删除事件侦听器。我制作了一个函数,它将向按钮添加事件侦听器,但如果该函数再次运行,我希望删除并再次添加事件侦听器。但相反,它只会添加另一个事件侦听器,当我单击按钮时,它将运行事件侦听器函数两次。或者即使我可以阻止它向按钮添加第二个事件侦听器也可以。

这里是代码

<button id="myId">My Button</button>
 
 
 
<script>
 
 
 
myFunction()
myFunction()
 
function myFunction() 
     var el = document.getElementById('myId')
 
     var listenerFn = function () 
          console.log('My Message')
     
 
     el.removeEventListener('click', listenerFn)
 
     el.addEventListener('click', listenerFn)

 
 
 
</script>

任何提示都会很有帮助。

更新:

@FathiAlqa​​dasi 的答案是迄今为止我的问题的最佳答案。但我应该展示更多的代码。侦听器功能是动态的,并且可以根据其功能而有所不同。这是我的意思的另一个例子。

<button id="myId">My Button</button>



<script>

myFunctionA()
myFunctionA()



function myFunctionA() 
    var el = document.getElementById('myId')
    myFunctionB()
    function myFunctionB() 
        if (el.innerhtml === 'My Button') 
            var listenerFn = function () 
                console.log('My Message 1')
            

               el.removeEventListener('click', listenerFn);

            el.addEventListener('click', listenerFn);
        

        else 
            var listenerFn = function () 
                console.log('My Message 2')
            

               el.removeEventListener('click', listenerFn);

            el.addEventListener('click', listenerFn);
        
    

</script>

更新 2:

感谢@提供代码。这是一个整洁的代码框中的代码

<button id="myId">My Button</button>

<script>
    var listenerFn;
    myFunction();
    myFunction()
    function myFunction() 
        var el = document.getElementById('myId')
        el.removeEventListener('click', listenerFn);
        listenerFn = function() 
            console.log('My Message')
        
        el.addEventListener('click', listenerFn, false);
    
</script>

【问题讨论】:

【参考方案1】:

在本例中,我们在同一个函数中添加和删除监听器作为替代,以防止出现多余的监听器。

function callbackFunction() 
  console.log('Callback function was called.')


function addRemoveListener() 
  let el = document.getElementById('btn-test')

  el.removeEventListener('click', callbackFunction)
  el.addEventListener('click', callbackFunction)


addRemoveListener()
addRemoveListener()
&lt;button id="btn-test"&gt;Button&lt;/button&gt;

【讨论】:

您的代码确实可以工作,但当函数是动态的时,我应该在第一篇文章中展示它。阅读我的更新以了解更多信息。 您需要保存对处理函数的引用才能将其删除。试试这段代码,我只在 myFunction 【参考方案2】:

在使用事件侦听器时,我喜欢将它们存储在一个对象中,以便我可以跟踪已注册的内容并在必要时轻松删除它们。

在您的情况下,将在全局范围内创建一个简单的布尔值来检查您是否需要删除侦听器。 (添加监听器后设置为true)。

<button id="myId">My Button</button>



<script>

var removeListener = false;

myFunction()
myFunction()

function myFunction() 
     var el = document.getElementById('myId')

     var listenerFn = function () 
          console.log('My Message')
     

     if (removeListener) el.removeEventListener('click', listenerFn)

     el.addEventListener('click', listenerFn);
     removeListener = true;




</script>

更新 根据您的更新,我有一个修改后的答案。我仍然不清楚您为什么要两次调用该函数,但我们会认为这是给定的。

<button id="myId">My Button</button>



<script>
var listeners = ;

myFunctionA();
myFunctionA();



function myFunctionA() 
    var listenerFn1 = function()  //These functions need to be distinct so that we can refer to them when removing
        console.log('My Message 1')
    ;

    var listenerFn2 = function()  //We actually didn't need to move these out from where they were, but its a little easier to read this way
        console.log('My Message 2')
    ;

    function myFunctionB() 
        if (el.innerHTML === 'My Button') 
            if (listeners[el]) el.removeEventListener('click', listeners[el]);
            el.addEventListener('click', listenerFn1);
            listeners[el] = listenerFn1; //This could be expanded to account for different events, but keeping it simple for this scenario
        
        else 
            if (listeners[el]) el.removeEventListener('click', listeners[el]);
            el.addEventListener('click', listenerFn2);
            listeners[el] = listenerFn2;
        
    

    var el = document.getElementById('myId');
    myFunctionB();

</script>

这里的重点是要有一个对象来存储事件触发时调用的函数。该对象可以允许不同的事件,例如:

var listener = ;
var el = document.getElementById('myId');

...

//Check if a click listener exists for el
if (listener[el] && listener[el].click) 
  //Remove currently registered listener
  el.removeEventListener('click', listener[el].click);

listener[el] = listener[el] || ; //If listener[el] does not exist, create it
listener[el].click = function() 
  //We can use an anonymous function in this case because we do not need to compare it to any other functions
  console.log('Click 1');
;
el.addEventListener('click', listener[el].click);

如果您希望允许将多个事件附加到侦听器,则不能使用匿名函数,因为您要确保不会两次添加相同的函数。

var listener = ;
var el = document.getElementById('myId');

...

var eventHandler1 = function() 
  console.log('eventHandler1');
;
var eventHandler2 = function() 
  console.log('eventHandler2');
;
//Check if a click listener exists for el that uses eventHandler1
if (listener[el] && listener[el].click && listener[el].click.includes(eventHandler1)) 
  //Remove listener with eventHandler1
  el.removeEventListener('click', listener[el].click.filter(function(val) 
    return val === eventHandler1;
  ));

listener[el] = listener[el] || ; //If listener[el] does not exist, create it
listener[el].click = listener[el].click || [];
listener[el].click.push(eventHandler1);
el.addEventListener('click', eventHandler1);

【讨论】:

【参考方案3】:

在 JS 中,函数是对象类型,这意味着它们是引用类型。我的意思是你每次运行myFunction;

function myFunction() 
     var el         = document.getElementById('myId'),
         listenerFn = function () 
                        console.log('My Message')
                      ;

     el.removeEventListener('click', listenerFn)
     el.addEventListener('click', listenerFn)

您创建了一个单独的listenerFn,因此removeEventLister() 可以区分它们,因为removeEventListener() 的参数必须引用先前设置的事件监听器函数。

你应该这样做;

<button id="myId">My Button</button>

<script>

function listenerFn() 
  console.log('My Message')


function myFunction() 
   var el = document.getElementById('myId')
   el.removeEventListener('click', listenerFn)
   el.addEventListener('click', listenerFn)


myFunction();

</script>

【讨论】:

【参考方案4】:

或者即使我可以阻止它向按钮添加第二个事件侦听器也可以。

此示例将只添加一次侦听器。我使用dataset 作为标志来了解按钮是否正在监听。但是,我强烈建议您使用 GlobalEventHandlers.onclick 像这里:btnRemove.onclick = removeBtnListener 它更干净,而且您将 100% 确定只添加了一个功能。

function callbackFunction() 
  console.log('Callback function was called.')


function removeBtnListener() 
  const btn = document.getElementById('btn-test')

  if (btn.dataset.listening) 
    btn.removeEventListener('click', callbackFunction)
    delete btn.dataset.listening

    console.log('Listener removed.')
  


function initListener() 
  let btn = document.getElementById('btn-test')

  if (!btn.dataset.listening) 
    btn.addEventListener('click', callbackFunction)
    btn.dataset.listening = true

    console.log('Listener added.')
  


window.onload = function() 
  let btnRemove = document.getElementById('btn-remove')
  btnRemove.onclick = removeBtnListener

  initListener()
  initListener()
  initListener()
  initListener()
<button id="btn-test">Button</button>
<button id="btn-remove">Remove Listener</button>

【讨论】:

以上是关于删除重复的事件侦听器的主要内容,如果未能解决你的问题,请参考以下文章

jquery,添加和删除事件处理程序[重复]

事件侦听器(滚动)重复运行

侦听DialogFragment从ViewPager Fragment中删除事件

单击表单内的事件侦听器[重复]

单击 ListActivity 中的事件侦听器 [重复]

元素 innerHTML 摆脱了事件侦听器 [重复]