【问题标题】:Can't remove event listener无法移除事件监听器
【发布时间】:2015-11-26 07:52:18
【问题描述】:

谁能说出为什么bt2 事件侦听器没有在if 块中被删除。当我在p 函数中删除事件侦听器时,它会被删除而没有任何错误或错误。我很确定可能存在任何堆栈或范围问题,因为哪个事件侦听器没有被删除,但我不知道那可能是什么。而且我知道事件侦听器没有被删除,因为对bt2 元素的后续点击所有前面的事件侦听器也再次运行,因为同一个函数运行了多次。请告诉我有什么问题。

这是完整的代码:

    (function()
    {
        if(window.addEventListener) window.addEventListener('load',init,false);
        function init()
        {   var i=0;
            var get=document.getElementById('bt1').addEventListener('click',function() { pro(0);},false);

            function pro(x)
            {   alert('yeah');
                if(!x) x=0
                if(x!=0) //I dont want to remove event listener in the first time , so i want it to function with the next call to pro,in which the value of x is bigger than 0                
{
                    //alert('right'); 
                      document.getElementById('bt2').removeEventListener('click',p,false); //event listener is not getting removed .
                }
                document.getElementById('bt2').innerHTML='this is a button '+x;
                function passTo(y)
                {   
                    pro(y);     
                }
                document.getElementById('bt2').addEventListener('click',p,false);
                function p()
                {   //document.getElementById('bt2').removeEventListener('click',p,false); //here the event listener is getting removed easily
                    passTo(x+1);
                }

            }
        }
    }());

【问题讨论】:

    标签: javascript event-handling dom-events


    【解决方案1】:

    removeEventListener 要求您传递相同的函数,但您的p 函数不一样:每次调用pro 时都会创建一个新函数。因此,您要删除的不是您添加的那个,因此它不会被删除。

    p 中删除它是有效的,因为在每个p 函数中,标识符p 指的是特定的p 函数。因此,如果添加了那个,它将成功删除自己。

    您可以通过在您的函数上放置一个唯一标识符来向自己证明这一点(请参阅 cmets):

    (function() {
        if (window.addEventListener) window.addEventListener('load', init, false);
    
        var functionId = 0; // Something to give us unique IDs
    
        function init() {
            var i = 0;
            var get = document.getElementById('bt1').addEventListener('click', function() {
                pro(0);
            }, false);
    
            function pro(x) {
                snippet.log('yeah');
                // We ALWAYS to into the body of this if, the condition
                // is just here for emphasis
                if (!p.id) {
                    p.id = ++functionId;
                }
                if (!x) x = 0
                if (x != 0)
                {
                    snippet.log("Removing #" + p.id); // <===
                    document.getElementById('bt2').removeEventListener('click', p, false);
                }
                document.getElementById('bt2').innerHTML = 'this is a button ' + x;
    
                function passTo(y) {
                    pro(y);
                }
                snippet.log("Adding #" + p.id); // <===
                document.getElementById('bt2').addEventListener('click', p, false);
    
                function p() { 
                    passTo(x + 1);
                }
    
            }
        }
    }());
    <button id="bt1">bt1</button>
    <button id="bt2">bt2</button>
    
    <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
    <script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

    如果我们运行它并单击一次bt1,然后重复单击bt2,我们会看到:

    是的 添加#1 是的 删除 #2 添加#2 是的 删除 #3 添加#3 是的 删除 #4 添加#4

    请注意每次我们如何尝试删除与添加的不同函数。

    如果要删除之前的,需要在别处记住(见cmets)

    (function() {
        if (window.addEventListener) window.addEventListener('load', init, false);
    
        var functionID = 0;
        var lastp = null; // <===
    
        function init() {
            var i = 0;
            var get = document.getElementById('bt1').addEventListener('click', function() {
                pro(0);
            }, false);
    
            function pro(x) {
                snippet.log('yeah');
                if (!p.id) { // Again, always true
                    p.id = ++functionID;
                }
                if (!x) x = 0;
                if (lastp) // <===
                {
                    snippet.log("Removing #" + lastp.id);
                    document.getElementById('bt2').removeEventListener('click', lastp, false);
                }
                document.getElementById('bt2').innerHTML = 'this is a button ' + x;
    
                function passTo(y) {
                    pro(y);
                }
                lastp = p; // <===
                snippet.log("Adding #" + p.id);
                document.getElementById('bt2').addEventListener('click', p, false);
    
                function p() { 
                    passTo(x + 1);
                }
    
            }
        }
    }());
    <button id="bt1">bt1</button>
    <button id="bt2">bt2</button>
    
    <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
    <script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

    【讨论】:

    • 有没有办法分叉你的snippet.js
    • @JonatasWalker:它在 github 上,所以是的。我只希望 SE 能够解决 Stack Snippets。
    • 我从没想过它们不是同一个函数,所以引用会有所不同,现在我将 p 函数设为全局,并且代码运行良好,谢谢,您的建议有效!我被它震惊了好几天@T.J.Crowder !!