【问题标题】:Why is dragleave event firing unexpectedly?为什么dragleave事件意外触发?
【发布时间】:2014-01-06 19:57:57
【问题描述】:

请在http://jsfiddle.net/fSB32/2/查看演示

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

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

【问题讨论】:

  • 如果人们解释为什么他们投反对票或投票结束,这将是建设性的。这样我下次可以提出更好的问题。

标签: jquery html drag-and-drop


【解决方案1】:

我自己解决了这个问题。

原因

拖动事件在链上冒泡。因此,令我震惊的是,正因为如此,当我使叠加层可见时,它触发了dragenter,并且可能在进一步拖动dragleave 时,它的孩子正在触发dragleave,它会冒泡到我正在听的父母那里。

然而,事实证明,每当dragenter 被触发时,dragleave 就会被触发,即使dragenter 目标是一个孩子!因此,在我的情况下,当我使叠加层可见时,dragenter 被触发,dragleave 被触发 documentwindow

修复

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

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

查看演示http://jsfiddle.net/fSB32/5/

如果您确实需要支持低于 11 的 IE,那么可以使用一个技巧将一个空 div 作为子级放置在放置目标中,并确保它具有最高的 z-index 并覆盖整个放置目标。这种方式拖动事件应该只定向到这个 DOM,因为所有其他的孩子都是“通过”它可见的。

【讨论】:

    【解决方案2】:

    这是一个没有子限制的“双击”解决方案。

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

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

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

    问题:由于表单输入和图像的所有内容都在 DIV 子项中,因此“dragleave”被触发,即使它没有离开虚线。使用属性“pointer-events: none”不是替代方法,因为方法 3 和 4 需要触发“onchange”事件。

    解决方案?一个重叠的 DIV,当鼠标进入时覆盖所有的 drop-container,并且唯一的一个具有“pointer-events: none”的子元素。

    结构:

    • div #drop-container:主 div,将所有内容放在一起
    • div #drop-area:“dragenter”监听器和中间触发器#drop-pupup
    • div #drop-pupup:与#drop-area、“dragenter”、“dragleave”和“drop”监听器处于同一级别

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

    这里是 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一起使用,这样你就可以启动事件触发器,启动“上传框”隐藏。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-29
      • 2011-02-07
      • 2012-08-18
      • 2015-05-03
      • 2020-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多