在离开页面之前删除事件侦听器

moo*_*her 1 javascript drag-and-drop onbeforeunload event-listener onunload

我开发了一个 javascript 拖放,主要使用标准的 'allowdrop'、'drag' 和 'drop' 事件。

我想自定义“幻影”拖动对象,因此我添加了一个 display:none div,它填充了可拖动元素的 innerHTML 并在用户开始拖动时使其可见 (display:block;)。

可拖动的 div 绝对定位并匹配鼠标移动。为此,我需要向 document.body 添加 3 个事件侦听器。它们如下:

document.body.addEventListener('dragover', function (ev) {
    console.log("dragover event triggered");
    ev = ev || window.event;
    ev.preventDefault();
    dragX = ev.pageX;
    dragY = ev.pageY;
    document.getElementById("dragged-container").style.left = (dragX - dragOffsetX) + "px";
    document.getElementById("dragged-container").style.top = (dragY - dragOffsetY - 10) + "px";    
    if (mostRecentHoveredDropTargetId!="") {
        if (dragX<mostRecentHoveredDropTargetRect.left || dragX>mostRecentHoveredDropTargetRect.right || dragY<mostRecentHoveredDropTargetRect.top || dragY>mostRecentHoveredDropTargetRect.bottom) {
            document.getElementById(mostRecentHoveredDropTargetId).classList.remove("drop-target-hover");
            mostRecentHoveredDropTargetId = "";
        }
    }
});

document.body.addEventListener('drop', function (ev) {
    console.log("drop event triggered");
    ev.preventDefault();
    var data = ev.dataTransfer.getData("text"); // data set to the id of the draggable element
    if (document.getElementById(data)!=null) {
        document.getElementById(data).classList.remove("dragged");
        document.getElementById("dragged-container").innerHTML = "";
        document.getElementById("dragged-container").style.display = "none";
        var draggablesClasses = document.getElementById(data).className;
        if ((draggablesClasses.indexOf('draggable')==-1 || draggablesClasses=="") && document.getElementById(data).getAttribute('draggable')=="true") {
            if (draggablesClasses=="") {
                document.getElementById(data).className += "draggable";
            } else {
                document.getElementById(data).className += " draggable";
            }
        }
    }
});

// resets dragged-container and origin .draggable, when mouse released outside browser window
document.body.addEventListener('mouseleave', function (ev) {
    if (jqueryReady==true) {
        $(".dragged").addClass("draggable");
        $(".dragged").removeClass("dragged");
    }
    document.getElementById("dragged-container").innerHTML = "";
    document.getElementById("dragged-container").style.display = "none";
});
Run Code Online (Sandbox Code Playgroud)

这一切正常。拖放的表现完全符合我的预期。

问题是当我转到另一个页面时,显然那些正文事件侦听器仍在运行。

我在这里看到了许多答案,并尝试了我所看到的一切。对于初学者来说:

window.onunload = function() {
    console.log("about to clear event listeners prior to leaving page");
    document.body.removeEventListener('dragover', null);
    document.body.removeEventListener('drop', null);
    document.body.removeEventListener('mouseleave', null);
    return;
} 
Run Code Online (Sandbox Code Playgroud)

...但console.log 输出甚至没有出现(更不用说'null's 是错误的,我很确定)。我也试过这个,在 jQuery 就绪函数中:

$(window).bind('beforeunload', function(){
        console.log("about to clear event listeners prior to leaving page");
        document.body.removeEventListener('dragover', null);
        document.body.removeEventListener('drop', null);
        document.body.removeEventListener('mouseleave', null);
    });
Run Code Online (Sandbox Code Playgroud)

..但是,再一次,控制台甚至没有收到该输出。

我也试过上面的“onbeforeunload”和“onunload”。

我究竟做错了什么?- 特别是删除这些 window.body 事件侦听器,我的意思是(我以后可以解决的任何其他问题)。

谢谢。

小智 6

removeEventListener 需要处理程序

不要使用匿名函数是解决方案。像这样:

var dragHandler = function (ev) {
    console.log("dragover event triggered");
};
document.body.addEventListener('dragover', dragHandler);
Run Code Online (Sandbox Code Playgroud)

之后:

window.onunload = function() {
    console.log("about to clear event listeners prior to leaving page");
    document.body.removeEventListener('dragover', dragHandler);
    return;
}
Run Code Online (Sandbox Code Playgroud)