jQuery Droppables - Problems when hiding 'inactive' drop zones
I've got a fairly long list of divs which I'm trying to use as droppable's - but I want to hide all of the droppables that won't accept the current draggable element.
I've put an example up at http://jsfiddle.net/N3uh3/
Basically if I drag the 'Drag A' element it will hide all 'Droppable B' elements and allow me to drop onto the correct elements and this works well.
However if I drag the 'Drag B' element it will hide all 'Droppable A' elements but the remaining drop areas do not accept my draggable item. If I drop the item at the original location of the 'Droppable B' elements then it drops correctly (even though the position of the element has moved). If I use "visibility: hidden;" instead of "display:none" this also works as the element does not move.
I hope this makes sense - seems like the droppable area is set to the original position of the element....is there any way around this?
.lhs { width: 40%; float:left; }
.rhs { width: 40%; float:right; }
.lhs div { margin: 4px; }
.a { background-color: green; }
.b { background-color: red; }
.ui-state-highlight { background-color: yellow; }
.dropZones .ui-droppable { display: none; }
.dropZones .ui-state-highlight { display: block; }
.currentDropZone { display: block; }
<div class="wrapper">
<div class="lhs">
<div class="a">DROP A</div>
<div class="a">DROP A</div>
<div class="a">DROP A</div>
<div class="a">DROP A</div>
<div class="a">DROP A</div>
<div class="a">DROP A</div>
<div class="b">DROP B</div>
<div class="b">DROP B</div>
<div class="b">DROP B</div>
<div class="b">DROP B</div>
<div class="b">DROP B</div>
<div class="b">DROP B</div>
</div>
<div class="rhs">
<div class="a">Drag A</div>
<br />
<div class="b">Drag B</div>
</div>
</div>
$(document).ready(function(){
$('.rhs div').draggable({
helper: function (e,ui) {
// this sets the clone to be a child of the body - fixing overflow:auto problems on divs!
return $(this).clone().appendTo('body').css('zIndex',5).show();
},
revert: 'invalid',
cursor: 'move',
start: function(){
//$('.lhs').addClass('dropZones'); // immediately hides so doesn't get the ui-state-highlight class'
// give a quick period of time then add the class
setTimeout(function() { $('.lhs').addClass('dropZones'); }, 250);
},
stop: function(){
$('.lhs').removeClass('dropZones');
},
});
$('.lhs div').each(function(){
$(this).droppable({
greedy: true,
activeClass: 'ui-state-highlight',
accept: '.' + $(this).attr('class'),
drop: function(event, ui) {
$(this).append($(ui.draggable).clone());
},
activate: function(){
$(this).addClass('currentDropZone');
},
deacti开发者_运维知识库vate: function(){
$(this).removeClass('currentDropZone');
}
});
});
});
Thanks in advance!
The problem is that hiding your inactive droppables changes the element flow and positions of the active ones. By the time your delayed event fires, absolute droppable positions are already cached by jQuery UI, and that is what's checked when you let the mouse button go. In your original example you can still drop B
if you drag it to the old position of the B
dropzones, which is just under the visible list.
A quick and easy solution would be to tell jQuery UI to recalculate droppable positions on every mousemove by using the refreshPositions: true
option on the draggable. From the documentation:
refreshPositions: Boolean
If set to true, all droppable positions are calculated on every mousemove. Caution: This solves issues on highly dynamic pages, but dramatically decreases performance.
You updated demo: http://jsfiddle.net/N3uh3/1/
This is a quick fix, but my suggestion would be to make up your own logic when hiding your items rather than relying on setTimeout()
, which adds a noticeable annoying lag before hiding your droppables.
As only shown droppables are activated, I would add my hiding logic before jQuery UI even has a chance of building up a list of accepting droppables, like the mousedown
event on the items. Then you can do your own custom code to hide unwanted droppables, so when it comes to caching positions, they would be correct and there would be no need to refresh the cache on every mousemove, which might be an expensive operation depending on the number of droppables you have.
精彩评论