为什么dragleave事件意外触发?

时间:2014-01-06 19:57:57

标签: jquery html5 drag-and-drop

请参阅演示 - http://jsfiddle.net/fSB32/2/

我的意图是在document上触发拖动事件时会出现叠加层。因此,允许用户将图像拖放到文档的任何位置。当他这样做时会出现一个很酷的叠加层。在拖动事件完成时,叠加层应该隐藏自己。

我面临的问题是dragleave事件被意外触发(请参阅演示中的控制台),导致叠加层在出现时立即隐藏。如果您注释掉代码以隐藏叠加层,那么它自然会显示出来并且永远不会出现。

2 个答案:

答案 0 :(得分:8)

我自己想出了这个问题。

原因

将事件拖入链中。所以,让我感到震惊的是,因为当我使我的叠加层可见时,它触发了dragenter,并且可能在进一步拖动时dragleave被其子项触发,其中我的孩子冒泡到我父母那里我在听。

但是,即使dragleave目标是儿童,每当触发dragenter时都会触发dragenter!因此,就我而言,当我显示叠加层时,dragenter被触发,dragleavedocument触发了window

修复

因此理想的放置目标不能有任何子节点,因此在其内部拖动不会触发dragleave。在我的情况下,放置目标覆盖占用整个窗口空间,所以在我的情况下,仅在覆盖DOM上监听dragleave就足够了。这解决了90%的myc问题。

但是,当用户拖过其中的子div时,会出现问题。解决这个问题太容易了。我的要求是让我的孩子div对鼠标事件不可见。为此我们有神奇的CSS - pointer-events。将此属性设置为none可以解决问题。唯一的缺点是IE直到11都不支持。

请参阅演示http://jsfiddle.net/fSB32/5/

如果你确实需要支持低于11的IE,那么可以使用一个技巧将空div作为放置目标中的子项并确保它具有最高的z-index并且它覆盖了完整的放置目标。这样,拖动事件应仅针对此DOM,因为所有其他子项都可以“通过”它。

答案 1 :(得分:0)

这是不受孩子限制的“双击”解决方案。

正如所说的最佳答案,与“ mouseover”不同,事件“ dragover”和“ dragleave”并未将子元素视为一个整体,因此,每次鼠标经过任何一个子元素时,都会触发“ dragleave”

考虑文件上传,我创建了一个小部件,该小部件允许:

  1. 使用$ _FILES拖放桌面文件
  2. 使用$ _POST和cURL拖放到浏览器图像/元素或url
  3. 使用$ _FILES按钮来附加设备文件
  4. 使用输入通过$ _POST和cURL编写/粘贴url图片/元素

enter image description here

问题:由于所有形式的输入和图像都在DIV子级中,因此即使没有离开虚线,也会触发“ dragleave”。不能使用“指针事件:无”属性,因为方法3和4需要触发“ onchange”事件。

解决方案?重叠的DIV,当鼠标进入时会覆盖所有放置容器,唯一的一个子元素带有“指针事件:无”。

结构:

  • div#drop-container:主要div,保留所有提示信息
  • div#drop-area:“猛兽”侦听器和中间触发器#drop-pupup
  • div#drop-pupup:与#drop-area,“ dragenter”,“ dragleave”和“ drop”侦听器相同的水平

然后,当鼠标通过将元素拖动到#drop-area进入时,立即在前面显示#drop-pupup,随后事件将在该div上而不是初始接收者上。

enter image description here

这是JS / jQuery代码。我自由离开了PoC,所以不要在我迷路的时候一直迷路。

jQuery(document).on('dragover', '#drop-area', function(event) {
	event.preventDefault();
	event.stopPropagation();
	jQuery('#drop-popup').css('display','block');
});

jQuery(document).on('dragover dragleave drop', '#drop-popup', function(event) {
	event.preventDefault();
	event.stopPropagation();

	console.log(event.type);

	// layout and drop events
	if ( event.type == 'dragover') {
		jQuery('#drop-popup').css('display','block');
	}
	else {
		jQuery('#drop-popup').css('display','none');
	
		if ( event.type == 'drop' ) {
			// do what you want to do
			// for files: use event.originalEvent.dataTransfer.files
			// for web dragged elements: use event.originalEvent.dataTransfer.getData('Text') and CURL to capture
		}
	}
});
body {
  background: #ffffff;
  margin: 0px;
  font-family: sans-serif;
}

#drop-container {
  margin: 100px 10%; /* for online testing purposes only */
  width: 80%; /* for jsfiddle purposes only */
  display: block;
  float: left;
  overflow: hidden;
  box-sizing: content-box;
  position: relative; /* needed to use absolute on #drop-popup */
  border-radius: 5px;
  text-align: center;
  cursor: default;
  border: 2px dashed #000000;
}

#drop-area {
  display: block;
  float: left;
  padding: 10px;
  width: 100%;
}

#drop-popup {
  display: none;
  box-sizing: content-box;
  position: absolute;
  width: 100%;
  top: 0;
  left: 0;
  background: linear-gradient(to BOTTOM, rgba(245, 245, 245, 1) , rgba(245, 245, 245, 0));
  height: 512px;
  padding: 20px;
  z-index: 20;
}

#drop-popup > p {
   pointer-events: none;
}
<html>
  <head>
    <title>Drag and Drop</title>
  </head>
  <body>

    <div id="drop-container">
      <div id="drop-area">
        <p>Child paragraph content inside drop area saying "drop a file or an image in the dashed area"</p>
        <div>This is a child div No. 1</div>
        <div>This is a child div No. 2</div>
      </div>
      <div id="drop-popup">
        <p>This DIV will cover all childs on main DIV dropover event and current P tag is the only one with CSS "pointer-events: none;"</p>
      </div>
    </div>
    
    <script src="https://code.jquery.com/jquery-3.4.1.min.js" type="text/javascript"></script>
  </body>
<html>

关于jQuery“ on”,将其与div id一起使用,这样您就可以启动事件触发器,从而隐藏“ uploading box”。

最后,相对于“ dragoner”,我更喜欢使用“ dragover”,因为它具有较小的延迟(毫秒),有利于性能 (https://developer.mozilla.org/en-US/docs/Web/API/Document/dragover_event)。

相关问题