jQuery可放置和可滚动的div
我对jQuery UI的可放置组件有一点问题,但由于我的代码或组件中的错误,我不确定是否有这个问题。
我有一个固定宽度和高度的div。 该div的overflow-x设置为hidden,overflow-y设置为auto。 在那个div中,我有更多的div。 很多外部div开始滚动。 每个内部div都是一个droppable,接受一个在包装div之外的draggable。
如果我将可拖动项目拖放到包装器中的某个位置,一切正常。 问题是,如果我将元素放在包装器div的下方,甚至会触发drop事件。
我不太擅长解释这个问题; 因此,这里有一些代码可以重现问题:
http://jsfiddle.net/2p56Y/
只需拖放“拖动我!”即可。 使用滚动条在div下面的容器。 出乎意料的是,你会看到警报“掉线”。
现在有趣的事情:如果向下滚动到项目“Test28”,现在拖放包装器下方的拖动,则不会触发拖放事件。 看起来隐藏的元素在您放置它们时仍然可以访问。
那么,这是一个错误还是我需要以不同的方式编写代码以使其工作? (或两者? :-) )
检查droppable元素与父容器的边界,如果droppable的底部位于父级顶部之上或者droppable的顶部位于父级底部之下,则会中断该函数的执行:
$('.item').droppable( { activeClass: "ui-state-default", hoverClass: "ui-state-hover", accept: "#draggable", drop: function( event, ui ) { var cTop = $(this).closest(".box").position().top + parseInt($(this).closest(".box").css("margin-top")); var cBtm = $(this).closest(".box").position().top + parseInt($(this).closest(".box").css("margin-top")) + $(this).closest(".box").height(); var dTop = $(this).position().top + parseInt($(this).css("margin-top")); var dBtm = $(this).position().top + parseInt($(this).css("margin-top")) + $(this).height() if (dBtm > cTop && dTop < cBtm) { alert("Dropped."); } } });
示例: http : //jsfiddle.net/lthibodeaux/2p56Y/6/
我意识到它并不优雅,但似乎可行。 我承认只对该脚本进行粗略测试。
你已经接受了答案,虽然我认为我应该把它放在那里:
一个更优雅的解决方法(基于事件冒泡,并且只能真正处理可视性到一个级别,而不是递归)可以通过制作$('.box, .item').droppable()
并且因为默认情况下greedy:false
应该触发嵌套div的drop事件,然后是外部div。
像hasClass('box')
这样的简单元素检查意味着丢弃发生在一个有效的区域中,所以你需要做的只是在内部drop事件缓存中放入的元素,然后是外部div的drop事件(如上所述,只是片刻之后发生了这种情况。
如果你掉到外部div之外,即使内部div drop事件会触发,外部div也不会发生,所以除了无用的缓存事件之外什么也没发生。 唯一的问题是看起来有一个非贪婪的嵌套droppables的错误,jQuery示例http://jqueryui.com/demos/droppable/propagation.html甚至不能正常工作 – 它的行为就好像它使用事件捕获而不是事件冒泡…
唯一的另一个(可以说是更合理的)解释是我误解了嵌套的droppables是如何表现的。
最近解决了这个完全相同的问题所以我想在这里分享。
我要提到的第一件事是, 这里解决了涉及嵌套droppable和事件冒泡的类似问题。 下面的解决方案解决了非嵌套但重叠的droppables的问题。
问题(技术术语)
如果您使用他的指令查看OP的jsfiddle,您会注意到这两个DOM元素彼此独立并且生活在相同的DOM“级别”上。 然而,正如OP和其他一些人已经注意到的那样,jQuery UI的Droppable似乎将drop事件冒泡到了DOM元素,而内容溢出的内容则覆盖了目标droppable。
解决方案
在目标droppable中删除元素时设置标志。 检查底层DOM元素的drop事件中的标志。 如果此标志包含指示已在目标droppable中删除的值,则返回false,不执行任何操作或还原。 无论你想做什么来忽略掉落事件。
对于我的特殊情况,我通过一个简单的属性值将我的标志设置为目标droppable的drop事件中的ui.helper,如下所示:
$(ui.helper).attr('ignore-drop-event', "true");
在underlapping droppable上的冒泡drop事件中,我检查此属性是否设置为true:
if ($(ui.helper).attr('ignore-drop-event') === "true") { // Ignore this drop event since it occurred as part of event bubbling } else { // This is a "real" drop event }
该解决方案依赖于以下假设
-
事件冒泡顺序是一致的。 意味着目标droppable将始终在underlapping droppable元素之前接收事件。 我不知道这是否总是如此,但这次评估在我的测试中是准确的。
-
在冒泡掉落事件的标志检查之前定义属性值 。
希望这有助于其他人。