dragleave 事件正在内部子级上触发

问题描述 投票:0回答:4

我正在尝试使用 HTML5 拖放,并使可放置容器在可拖动元素位于其上方时更改其样式。 问题是,如果可放置容器包含内部元素,则会触发 Dragleave 事件,从而使容器失去其样式。

正如您所看到的,当可拖动元素进入小绿色框时。我们失去了外部 div 的红色边框。

<html>
<head>
<style>
.droptarget {
   
    width: 100px; 
    height: 100px;
    margin: 15px;
    margin-right: 100px;
    padding: 10px;
    border: 1px solid #aaaaaa;
}

.inner-droptarget {
  margin-left: 20px;
  margin-top: 20px;
width: 50px;
height: 50px;
border: 1px solid green
}
</style>
</head>
<body>



<p ondragstart="dragStart(event)" draggable="true" id="dragtarget">Drag me!</p>


<div class="droptarget" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" ondrop="drop(event)" ondragover="allowDrop(event)">

<div class="inner-droptarget">
</div>
</div>


<script>
function dragStart(event) {
    event.dataTransfer.setData("Text", event.target.id);
}

function dragEnter(event) {
    if ( event.target.className == "droptarget" ) {
        event.target.style.border = "3px dotted red";
    }
}

function dragLeave(event) {
    if ( event.target.className == "droptarget" ) {
        event.target.style.border = "";
    }
}


</script>

<p>
The border of the outside div should remain red even if dragging into the green div!
</p>


</body>
</html>

html drag-and-drop draggable drag droppable
4个回答
3
投票

您必须忽略在

"dragleave"
中包含的元素上触发的
"droptarget"
事件(例如
"inner-droptarget"
)。

为此,您可以检测事件是否是从放置区域的后代触发的。您的处理程序将如下所示:

function dragLeave(event) {
    if ( event.target.className == "droptarget" ) && !($('.droptarget').contains(event.fromElement) {
        event.target.style.border = "";
    }
}

1
投票

你可以使用计数器来解决这个问题。当draenter counter++时,当dragleave counter--并检查counter === 0时,然后做一些事情。

// div has an child element
divEl.addEventListen("dragenter",dragEnter)
divEl.addEventListen("dragleave",dragLeave)
counter = 0

function dragEnter(){
 counter++
}

function dragLeave(){
  counter--
  if(counter === 0){
    // then do something
  }

}

0
投票

当您在拖动过程中进入内部 div 时,将触发事件“拖动进入”和“拖动离开”事件。我们需要一种方法来标记您要离开外部 div 并进入内部 div,以便外部 div 上的边框保持红色。

我可以让两个边框都变成红色,但是当你留下类似的问题时,两个边框都会变回绿色。

<body> 
<p ondragstart="dragStart(event)" draggable="true" id="dragtarget">Drag me!</p> 
<div id="myOuterDiv" class="droptarget" ondragenter="dragEnter1(event)" 
ondragleave="dragLeave1(event)" 
ondrop="drop(event)" 
ondragover="allowDrop(event)"> 
<div id="myInnerDiv" class="inner-droptarget" ondragenter="dragEnter2(event)" 
ondragleave="dragLeave2(event)">
</div>
</div>  
<script>
var inOuter = false;
var inInner = false;
function dragStart(event) {
    event.dataTransfer.setData("Text", event.target.id);
}

function dragEnter1(event) { 
    inOuter = true; 
    document.getElementById("myInnerDiv").addEventListener("ondragenter", dragEnter2);
    console.log("entered outer");
    return highlightBorder();
}

function dragLeave1(event) {
console.log("left outer");
    inOuter = false;
    highlightBorder();
    event.preventDefault();
}
function dragEnter2(event) {
    console.log("entered inner");
        inInner = true;
        inOuter = true;
        return highlightBorder();  
        }

function dragLeave2(event) { 
console.log("left inner");
    inInner = false;
    inOuter = true;
    return highlightBorder();

}
function allowDrop(ev) {
    return false;
}
function drop(event) {
var inOuter = false;
var inInner = false;
    document.getElementById("myInnerDiv").style.border ="3px solid green";
    document.getElementById("myOuterDiv").style.border ="3px solid green";
     return false;
}
function highlightBorder() {
if( inInner)
{
    document.getElementById("myInnerDiv").style.border ="3px dotted red"; 
    document.getElementById("myOuterDiv").style.border ="3px dotted red";
    return false;
}
if(!inInner && inOuter)
{
    document.getElementById("myInnerDiv").style.border ="";
    document.getElementById("myOuterDiv").style.border ="3px dotted red";
    return false;
}
 if(!inInner && !inOuter) 
{
    document.getElementById("myInnerDiv").style.border ="";
    document.getElementById("myOuterDiv").style.border ="";
    return false;
}
} 
</script>

<p>
The border of the outside div should remain red even if dragging into the green div!
</p>


</body>
</html>

0
投票

dragleave
事件的行为确实会在子元素上触发,这通常不是您想要的反应。因此,有多种技术可以检测 Dragleave 何时实际指示用户的拖动何时退出预期的放置区域。

  • 由于一个古老的开放错误,涉及递增和递减计数器的技术在 Firefox 中不起作用。
  • 涉及
  • pointer-events: none
     的技术使用户无法单击拖放区内的按钮。
  • 当 dropzone 包含 Shadow-dom Web 组件时,涉及检查遏制的技术通常会失败。
以下技术似乎效果更好。它涉及检查鼠标光标是否位于视口或放置区域之外。我已经在 Chrome 和 Firefox 中测试过它。

function dragleave_has_exited_current_target(event: DragEvent) { const mouse_is_outside_viewport = !event.relatedTarget || ( event.clientX === 0 && event.clientY === 0 ) if (mouse_is_outside_viewport) return true const rect = (event.currentTarget as any).getBoundingClientRect() const withinX = event.clientX >= rect.left && event.clientX <= rect.right const withinY = event.clientY >= rect.top && event.clientY <= rect.bottom const mouse_is_outside_current_target = !(withinX && withinY) return mouse_is_outside_current_target }
您可以在任何 Dragleave 侦听器中使用此技术,如下所示:

function dragleave(event) { if (dragleave_has_exited_current_target(event)) { // proceed with your own logic here remove_dropzone_indicator() } }
请注意,在 javascript 中,

event.currentTarget

 是您附加事件侦听器本身的元素 - 这意味着,为了使此技术逐字工作,您必须将 Dragleave 侦听器直接附加到预期的 dropzone 元素上。

© www.soinside.com 2019 - 2024. All rights reserved.