jQuery dragenter 或 dragover 包含子项
Posted
技术标签:
【中文标题】jQuery dragenter 或 dragover 包含子项【英文标题】:jQuery dragenter or dragover to include children 【发布时间】:2015-01-01 14:01:45 【问题描述】:我目前正在编写一个上传脚本,当然它具有拖放功能。
然而当我将文件拖到我的元素上时,我试图让它工作,它添加了类 drag-over 但是因为我的元素有子元素,它会不断触发,因为它会进入和离开元素。
我想知道如何扩展 *dragenter* / *dragover*
以包含主要元素 children?
这是我的代码的精简版(请注意我已禁用文件输入):
$(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 & 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>
【问题讨论】:
第 3 行可能出现错误:$(this).preventDefault();你可能想传入事件对象然后调用 event.preventDefault() 【参考方案1】:解决了!!
这是一个简单的例子,而不是 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 & 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>
【讨论】:
为什么 bind 有效但 on 无效。我被告知要为所有听众使用 $.fn.on。 这不能正常工作,目的是要有一个恒定的拖动类,这个解决方案有一个刷新行为,没有拖动类有几次闪烁......【参考方案2】:显然,这个问题比我想象的更频繁,因为我发现至少 5 个问题与同一主题相关。
与“mouseover”不同,“dragover”和“dragleave”事件不会将子元素视为一个整体,因此每次鼠标经过任何一个子元素时,都会触发“dragleave”。
考虑到文件的上传,我创建了一个小部件,它允许:
-
使用 $_FILES 拖放桌面文件
使用 $_POST 和 cURL 拖放到浏览器图像/元素或 url
使用 $ _FILES 按钮附加设备文件
使用输入通过 $_POST 和 cURL 写入/粘贴 url 图像/元素
问题:由于表单输入和图像的所有内容都在 DIV 子项中,因此“dragleave”被触发,即使它没有离开虚线。使用属性“pointer-events: none”不是替代方法,因为方法 3 和 4 需要触发“onchange”事件。
解决方案?一个重叠的 DIV,当鼠标进入时覆盖所有的拖放容器,并且唯一的一个具有“指针事件:无”的子元素。
结构:
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)。
【讨论】:
【参考方案3】:您可以通过样式简单地隐藏元素与鼠标交互:
例如将此添加到子元素中:
pointer-events: none;
不幸的是,IE 对此的支持不是很好:http://caniuse.com/#feat=pointer-events
【讨论】:
理想情况下,我想要一个跨浏览器修复,而不是“这将适用于这些,但不适用于这些”。这是生产级代码,因此需要 100% - 感谢您的回答! @JustSteveKing:是的,很抱歉。另一种方法是在拖动时更复杂地检查鼠标在什么地方(是否在父级内等)。 谢谢 :) 目前正在做一些事情。我正在考虑在触发 Dragover 之前将子元素绑定到父元素【参考方案4】:我找到了 2 个其他可行的解决方案。
仅当区域内没有其他控制器元素(编辑、删除)时才有效,因为此解决方案也会阻止它们:
#drop * pointer-events: none;
有一个better solution。
这个想法是,每次进入/悬停到/停留在一个新的子元素上时都会增加一个计数器,而当你离开其中一个子元素时会减少一个计数器。
$(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');
);
);
【讨论】:
以上是关于jQuery dragenter 或 dragover 包含子项的主要内容,如果未能解决你的问题,请参考以下文章
如何在事件 Dragover 或 Dragenter 中从 DataTransfer.getData 获取数据
如何在 dragover/dragenter HTML 5 拖放期间更改图标
HTML5拖放的dragover vs dragenter事件
ListView 的 DragEnter、DragOver、DragDrop 事件未引发 (AllowDrop=True)