我遇到的问题是,一个元素的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中都能运行。
我也遇到过同样的问题,下面是我的解决方案——我认为比上面的要简单得多。我不确定它是否跨浏览器(可能取决于冒泡顺序)
为了简单起见,我将使用jQuery,但解决方案应该是框架独立的。
事件以任意一种方式生成父节点,如下所示:
<div class="parent">Parent <span>Child</span></div>
我们附加事件
el = $('.parent')
setHover = function(){ el.addClass('hovered') }
onEnter = function(){ setTimeout(setHover, 1) }
onLeave = function(){ el.removeClass('hovered') }
$('.parent').bind('dragenter', onEnter).bind('dragleave', onLeave)
差不多就是这样。:)它可以工作,因为即使onEnter在子上先于onLeave在父上触发,我们延迟它稍微颠倒顺序,所以类先被删除,然后在一毫秒后重新应用。
您可以使用带有转换标志的超时并监听顶部元素。子事件中的Dragenter / dragleave将会弹出到容器中。
由于子元素的dragenter在容器的dragleave之前触发,我们将把标志显示设置为过渡1ms…dragleave监听器将在1毫秒结束之前检查标志。
该标志仅在转换到子元素时为真,而在转换到(容器的)父元素时为假。
var $el = $('#drop-container'),
transitioning = false;
$el.on('dragenter', function(e) {
// temporarily set the transitioning flag for 1 ms
transitioning = true;
setTimeout(function() {
transitioning = false;
}, 1);
$el.toggleClass('dragging', true);
e.preventDefault();
e.stopPropagation();
});
// dragleave fires immediately after dragenter, before 1ms timeout
$el.on('dragleave', function(e) {
// check for transitioning flag to determine if were transitioning to a child element
// if not transitioning, we are leaving the container element
if (transitioning === false) {
$el.toggleClass('dragging', false);
}
e.preventDefault();
e.stopPropagation();
});
// to allow drop event listener to work
$el.on('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
});
$el.on('drop', function(e) {
alert("drop!");
});
jsfiddle: http://jsfiddle.net/ilovett/U7mJj/
是否有可能阻止dragleave在拖动到子元素时发射?
Yes.
#drop * {pointer-events: none;}
CSS似乎足够Chrome。
当使用它与Firefox, #drop不应该有文本节点直接(否则有一个奇怪的问题,一个元素“离开它自己”),所以我建议只留下一个元素(例如,使用一个div在#drop里面放所有的东西)
下面是一个jsfiddle解决原始问题(损坏的)示例。
我还从@Theodore Brown的例子中做了一个简化版本,但只基于这个CSS。
不过,并不是所有浏览器都实现了这种CSS:
http://caniuse.com/pointer-events
看到Facebook的源代码,我可以找到这个指针事件:无;但是,它可能多次与优雅的降级回退一起使用。至少它是如此简单,解决了许多环境中的问题。