我遇到的问题是,一个元素的dragleave事件是在悬停该元素的子元素时触发的。同样,当再次悬停回父元素时,dragenter不会被触发。
我做了一个简化的小提琴:http://jsfiddle.net/pimvdb/HU6Mk/1/。
HTML:
<div id="drag" draggable="true">drag me</div>
<hr>
<div id="drop">
drop here
<p>child</p>
parent
</div>
使用以下JavaScript:
$('#drop').bind({
dragenter: function() {
$(this).addClass('red');
},
dragleave: function() {
$(this).removeClass('red');
}
});
$('#drag').bind({
dragstart: function(e) {
e.allowedEffect = "copy";
e.setData("text/plain", "test");
}
});
它应该做的是,当拖拽一些东西时,通过将drop div设置为红色来通知用户。这是可行的,但是如果你拖动到p子元素中,拖动键就会触发,div就不再是红色了。移动回下拉div也不会使它再次变红。有必要完全移出拖放div,并再次拖回它,使其变为红色。
是否有可能阻止dragleave在拖动到子元素时发射?
2017年更新:TL;DR,查找CSS指针事件:无;如@ h.d.所述。在现代浏览器和IE11中都能运行。
这是我的解决方案(https://jsfiddle.net/42mh0fd5/8):
<div id="droppable">
<div id="overlay"></div>
<a href="">test child 1</a>
<br /><br />
<button>test child 2</button>
<br /><br />
<button>test child 3</button>
<br />
</div>
<p id="draggable" draggable="true">This element is draggable.</p>
<script type="text/javascript">
var dropElem = document.getElementById('droppable');
var overlayElem = document.getElementById('overlay');
overlayElem.addEventListener('drop', function(ev) {
ev.preventDefault();
console.log('drop', ev.dataTransfer.files)
overlayElem.classList.remove('dragover')
dropElem.classList.add('dropped')
console.log('drop')
}, false);
overlayElem.addEventListener('dragover', function(ev) {
ev.preventDefault();
}, false);
overlayElem.addEventListener('dragleave', function(ev) {
console.log('dragleave')
overlayElem.classList.remove('dragover')
}, false);
dropElem.addEventListener('dragenter', function(ev) {
console.log('dragenter')
overlayElem.classList.add('dragover')
}, false);
</script>
<style>
#draggable{
padding:5px;
background: #fec;
display: inline-block;
}
#droppable{
width: 300px;
background: #eef;
border: 1px solid #ccd;
position: relative;
text-align: center;
padding:30px;
}
#droppable.dropped{
background: #fee;
}
#overlay.dragover{
content:"";
position: absolute;
z-index: 1;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,.2);
border:3px dashed #999;
}
</style>
我知道这是一个老问题,但我想补充我的偏好。我处理这个通过添加类触发css:后元素在更高的z-index然后你的内容。这样可以过滤掉所有的垃圾。
.droppable{
position: relative;
z-index: 500;
}
.droppable.drag-over:after{
content: "";
display:block;
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
z-index: 600;
}
然后只需在您的第一个dragenter事件上添加拖拽类,并且不再有子元素触发该事件。
dragEnter(event){
dropElement.classList.add('drag-over');
}
dragLeave(event){
dropElement.classList.remove('drag-over');
}
是否有可能阻止dragleave在拖动到子元素时发射?
Yes.
#drop * {pointer-events: none;}
CSS似乎足够Chrome。
当使用它与Firefox, #drop不应该有文本节点直接(否则有一个奇怪的问题,一个元素“离开它自己”),所以我建议只留下一个元素(例如,使用一个div在#drop里面放所有的东西)
下面是一个jsfiddle解决原始问题(损坏的)示例。
我还从@Theodore Brown的例子中做了一个简化版本,但只基于这个CSS。
不过,并不是所有浏览器都实现了这种CSS:
http://caniuse.com/pointer-events
看到Facebook的源代码,我可以找到这个指针事件:无;但是,它可能多次与优雅的降级回退一起使用。至少它是如此简单,解决了许多环境中的问题。