Javascript jQuery dragenter 或 dragover 以包含孩子

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26756176/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:20:21  来源:igfitidea点击:

jQuery dragenter or dragover to include children

javascriptjquerydrag-and-drop

提问by JustSteveKing

I am working on an upload script at the moment, and of course it has drag and drop capabilities.

我目前正在编写一个上传脚本,当然它具有拖放功能。

HoweverI am trying to get this to work when I drag a file over my element it adds the class drag-overhowever because my element has children it is constantly firing because it enters and leaves the element.

但是,当我将文件拖到我的元素上时,我试图让它工作,它会添加类拖拽,但是因为我的元素有子元素,它会不断触发,因为它进入和离开元素。

What I want to knowis how can I expand the *dragenter* / *dragover*to include the main elements children also?

我想知道的是如何扩展*dragenter* / *dragover*以包括主要元素儿童?

Here is a trimmed down version of my code (please note I have disabled the file input):

这是我的代码的精简版本(请注意我已禁用文件输入):

$(document).ready(function(){
    $(window).on('dragenter', function(){
        $(this).preventDefault();
    });
    $('#drag-and-drop-zone').on('dragenter', function(){
        $(this).addClass('drag-over');
    });
    $('#drag-and-drop-zone').on('dragleave', function(){
        $(this).removeClass('drag-over');
    });
});
.uploader
{
    width: 100%;
    background-color: #f9f9f9;
    color: #92AAB0;
    text-align: center;
    vertical-align: middle;
    padding: 30px 0px;
    margin-bottom: 10px;
    border-radius: 5px;
    font-size: 200%;
    box-shadow: inset 0px 0px 20px #c9afb2;
    cursor: default;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.uploader div.or {
    font-size: 50%;
    font-weight: bold;
    color: #C0C0C0;
    padding: 10px;
}

.uploader div.browser label {
    background-color: #ffffff;
    border: 2px solid #f44;
    padding: 5px 15px;
    color: #f44;
    padding: 6px 0px;
    font-size: 40%;
    font-weight: bold;
    cursor: pointer;
    border-radius: 2px;
    position: relative;
    overflow: hidden;
    display: block;
    width: 300px;
    margin: 20px auto 0px auto;
    transition: all 0.3s linear 0s;
}

.uploader div.browser span {
    cursor: pointer;
}

.uploader div.browser input {
    position: absolute;
    top: 0;
    right: 0;
    margin: 0;
    border: solid transparent;
    border-width: 0 0 100px 200px;
    opacity: .0;
    filter: alpha(opacity= 0);
    direction: ltr;
    cursor: pointer;
}

.uploader div.browser label:hover {
    background-color: #f44;
    color: #fff;
    border: 2px solid #fff;
}

.drag-over{
    border: 2px solid #00aef0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="uploader" id="drag-and-drop-zone">
    <div>Drag &amp; Drop Images Here</div>
    <div class="or">-or-</div>
    <div class="browser">
        <label>
            <span>Select Image</span>
            <input type="file" title="Click to add Images" accept="image/*" name="files" disabled="true">
        </label>
    </div>
</div>

回答by JustSteveKing

Solved it!!

解决了!!

It is a simple case of instead on on('dragenter')I needed to use bind('dragover')

这是一个简单的例子,而不是 on ('dragenter')我需要使用bind('dragover')

$(document).ready(function(){
    $(window).on('dragenter', function(){
        $(this).preventDefault();
    });
    $('#drag-and-drop-zone').bind('dragover', function(){
        $(this).addClass('drag-over');
    });
    $('#drag-and-drop-zone').bind('dragleave', function(){
        $(this).removeClass('drag-over');
    });
});
.uploader
{
    width: 100%;
    background-color: #f9f9f9;
    color: #92AAB0;
    text-align: center;
    vertical-align: middle;
    padding: 30px 0px;
    margin-bottom: 10px;
    border-radius: 5px;
    font-size: 200%;
    box-shadow: inset 0px 0px 20px #c9afb2;
    cursor: default;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.uploader div.or {
    font-size: 50%;
    font-weight: bold;
    color: #C0C0C0;
    padding: 10px;
}

.uploader div.browser label {
    background-color: #ffffff;
    border: 2px solid #f44;
    padding: 5px 15px;
    color: #f44;
    padding: 6px 0px;
    font-size: 40%;
    font-weight: bold;
    cursor: pointer;
    border-radius: 2px;
    position: relative;
    overflow: hidden;
    display: block;
    width: 300px;
    margin: 20px auto 0px auto;
    transition: all 0.3s linear 0s;
}

.uploader div.browser span {
    cursor: pointer;
}

.uploader div.browser input {
    position: absolute;
    top: 0;
    right: 0;
    margin: 0;
    border: solid transparent;
    border-width: 0 0 100px 200px;
    opacity: .0;
    filter: alpha(opacity= 0);
    direction: ltr;
    cursor: pointer;
}

.uploader div.browser label:hover {
    background-color: #f44;
    color: #fff;
    border: 2px solid #fff;
}

.drag-over{
    border: 2px solid #00aef0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="uploader" id="drag-and-drop-zone">
    <div>Drag &amp; Drop Images Here</div>
    <div class="or">-or-</div>
    <div class="browser">
        <label>
            <span>Select Image</span>
            <input type="file" title="Click to add Images" accept="image/*" name="files" disabled="true">
        </label>
    </div>
</div>

回答by Benjamin

Apparently this problem is more recurrent than I thought since I found at least 5 questions associated with the same topic.

显然这个问题比我想象的更经常出现,因为我发现了至少 5 个与同一主题相关的问题。

Unlike "mouseover", the events "dragover" and "dragleave" do not consider the child elements as a whole, so each time the mouse passes over any of the children, "dragleave" will be triggered.

与“mouseover”不同,“dragover”和“dragleave”事件不考虑子元素作为一个整体,所以每次鼠标经过任何一个子元素时,都会触发“dragleave”。

Thinking about the upload of files, I created a widget that allows:

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

  1. Drag and drop desktop files using $ _FILES
  2. Drag and drop to browser images/elements or url using $ _POST and cURL
  3. Attach a device file using button using $ _FILES
  4. Use input to write/paste url images/elements using $ _POST and cURL
  1. 使用 $_FILES 拖放桌面文件
  2. 使用 $_POST 和 cURL 拖放到浏览器图像/元素或 url
  3. 使用 $_FILES 使用按钮附加设备文件
  4. 使用输入写入/粘贴使用 $_POST 和 cURL 的 url 图像/元素

enter image description here

在此处输入图片说明

The problem: As everything, both form inputs and images, are within DIVs children, "dragleave" was triggered even if it did not leave the dashed line. Using the attribute "pointer-events: none" is not an alternative since methods 3 and 4 need to trigger "onchange" events.

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

The solution? An overlapping DIV that covers all the drop-container when the mouse enters, and the only one with child elements with "pointer-events: none".

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

The structure:

结构:

  • div #drop-container: main div, keep all togheter
  • div #drop-area: "dragenter" listener and inmediate trigger #drop-pupup
  • div #drop-pupup: at same leval as #drop-area, "dragenter", "dragleave" and "drop" listener
  • div #drop-container: 主 div,保持所有在一起
  • div #drop-area:“dragenter”监听器和中间触发器#drop-pupup
  • div #drop-pupup:与#drop-area、“dragenter”、“dragleave”和“drop”监听器处于同一级别

Then, when the mouse enters by dragging an element to #drop-area, inmediatly shows #drop-pupup ahead and successively the events are on this div and not the initial receiver.

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

enter image description here

在此处输入图片说明

Here is the JS/jQuery code. I took the liberty to leave the PoC so do not lose all the time I lost.

这是 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>

About jQuery "on", use it with the div id inside on, so you can start event triggers starting "uploading box" hidden.

关于 jQuery “on”,将其与里面的 div id 一起使用,这样您就可以启动事件触发器,开始隐藏“上传框”。

Finally, I preferred to use "dragover" over "dragenter" because it has a small delay (milliseconds) that favors performance (https://developer.mozilla.org/en-US/docs/Web/API/Document/dragover_event).

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

回答by Gone Coding

You can simply hide elements from the mouse interaction with styling:

您可以简单地隐藏鼠标与样式交互中的元素:

e.g. add this to the child elements:

例如,将其添加到子元素中:

pointer-events: none;

Unfortunately support is not great in IE for this: http://caniuse.com/#feat=pointer-events

不幸的是,IE 对此的支持不是很好:http: //caniuse.com/#feat=pointer-events

回答by Zoltán Süle

I found 2 other working solutions.

我找到了其他 2 个工作解决方案。

It works only if you do not have other controller elements (edit, delete) inside the area, because this solution blocks them too:

仅当您在该区域内没有其他控制器元素(编辑、删除)时才有效,因为此解决方案也会阻止它们:

#drop * {pointer-events: none;}

There is a better solution.

有一个更好的解决方案

The idea is that you increase a counter every time you enter/hover into/on a new child element and decrease the counter when you leave one of them.

这个想法是每次进入/悬停在新的子元素上时都会增加一个计数器,并在离开其中一个时减少计数器。

$(document).ready(function(){

    var dropzoneCounter = 0;

    $('#drag-and-drop-zone').on('dragenter', function(){
        dropzoneCounter++;
        $(this).addClass('drag-over');
    });

    $('#drag-and-drop-zone').bind('dragleave', function(){
        dropzoneCounter--;
        if (dropzoneCounter === 0) {
            $(this).removeClass('drag-over');
        }
    });

    $('#drag-and-drop-zone').bind('drop', function(){
        dropzoneCounter = 0;
        $(this).removeClass('drag-over');
    });
});