Возвратить объект jQuery перетаскиваемым обратно в оригинальный контейнер на случай десантирования
у меня есть перетаскиваемый элемент, который, если его не сбросить в droppable, вернется. Это работает хорошо, пока пользователь не отбрасывает элемент в droppable. Если они решат, что совершили ошибку в любое время, когда они вытаскивают перетаскиваемый, он возвращается к сбрасываемому. Я бы предпочел, чтобы on out и деактивировать перетаскиваемый возвращается к исходному контейнеру.
мой код ниже, но я предоставил образец на jsFiddle.
HTML
<div id="origin">
<div id="draggable" class="ui-widget-content">
<p>I revert when I'm not dropped</p>
</div>
</div>
<div id="droppable" class="ui-widget-header">
<p>Drop me here</p>
</div>
JavaScript
$(function() {
$("#draggable").draggable({
revert: function(dropped) {
var dropped = dropped && dropped[0].id == "droppable";
if(!dropped) alert("I'm reverting!");
return !dropped;
}
}).each(function() {
var top = $(this).position().top;
var left = $(this).position().left;
$(this).data('orgTop', top);
$(this).data('orgLeft', left);
});
$("#droppable").droppable({
activeClass: 'ui-state-hover',
hoverClass: 'ui-state-active',
drop: function(event, ui) {
$(this).addClass('ui-state-highlight').find('p').html('Dropped!');
},
out: function(event, ui) {
// doesn't work but something like this
ui.draggable.mouseup(function () {
var top = ui.draggable.data('orgTop');
var left = ui.draggable.data('orgLeft');
ui.position = { top: top, left: left };
});
}
});
});
6 ответов:
проверен С jquery 1.11.3 & jquery-ui 1.11.4
$(function() { $("#draggable").draggable({ revert : function(event, ui) { // on older version of jQuery use "draggable" // $(this).data("draggable") // on 2.x versions of jQuery use "ui-draggable" // $(this).data("ui-draggable") $(this).data("uiDraggable").originalPosition = { top : 0, left : 0 }; // return boolean return !event; // that evaluate like this: // return event !== false ? false : true; } }); $("#droppable").droppable(); });
Я не уверен, что это будет работать для вашего фактического использования, но это работает в вашем тестовом случае-Обновлено в http://jsfiddle.net/sTD8y/27/ .
Я просто сделал это так, что встроенный revert используется только в том случае, если элемент не был удален раньше. Если он был удален, возврат выполняется вручную. Вы можете настроить это для анимации до некоторого расчетного смещения, проверив фактические свойства CSS, но я позволю вам играть с этим, потому что многое зависит от CSS перетаскивать и окружающие структуры DOM.
$(function() { $("#draggable").draggable({ revert: function(dropped) { var $draggable = $(this), hasBeenDroppedBefore = $draggable.data('hasBeenDropped'), wasJustDropped = dropped && dropped[0].id == "droppable"; if(wasJustDropped) { // don't revert, it's in the droppable return false; } else { if (hasBeenDroppedBefore) { // don't rely on the built in revert, do it yourself $draggable.animate({ top: 0, left: 0 }, 'slow'); return false; } else { // just let the built in revert work, although really, you could animate to 0,0 here as well return true; } } } }); $("#droppable").droppable({ activeClass: 'ui-state-hover', hoverClass: 'ui-state-active', drop: function(event, ui) { $(this).addClass('ui-state-highlight').find('p').html('Dropped!'); $(ui.draggable).data('hasBeenDropped', true); } }); });
если вы хотите вернуть элемент в исходное положение, если он не упал внутри
#droppable
элемент, просто сохраните исходный родительский элемент перетаскиваемого в начале скрипта (вместо позиции), и если вы убедитесь, что он не упал в#droppable
, то просто восстановить родителя#draggable
к этому исходному элементу.так, замените это:
}).each(function() { var top = $(this).position().top; var left = $(this).position().left; $(this).data('orgTop', top); $(this).data('orgLeft', left); });
С этого:
}).each(function() { $(this).data('originalParent', $(this).parent()) });
здесь у вас будет исходный родительский элемент для перетаскивания. Теперь, вы должны восстановить его родителя в точный момент.
drop
вызывается каждый раз, когда элемент вытягивается из droppable, а не на остановке. Итак, вы добавляете много обратных вызовов событий. Это неправильно, потому что вы никогда не очиститеmouseup
событие. Хорошее место, где вы можете подключить обратный вызов и проверить, если элемент был сброшен внутри или снаружи#droppable
элемент, составляетrevert
, и вы делаете это прямо сейчас, так что, просто удалитеdrop
обратный звонок.когда элемент отброшен и должен знать, Следует ли его отменить или нет, вы точно знаете, что у вас не будет никакого другого взаимодействия с пользователем до начала нового перетаскивания. Итак, используя то же условие, которое вы используете, чтобы узнать, следует ли ему вернуться или узнать, давайте заменим это
alert
с фрагментом кода, который: восстанавливает родительский элемент в исходный div и сбрасываетoriginalPosition
Сdraggable
внутренние органы. ЭлементoriginalPosition
proeprty устанавливается в то время из_mouseStart
, так что, если вы измените владельца элемента, вы должны сбросить его, чтобы сделать анимацию revert перейти в нужное место. Итак, давайте установим это{top: 0, left: 0}
, делая анимацию перейти к исходной точке элемента:revert: function(dropped) { var dropped = dropped && dropped[0].id == "droppable"; if(!dropped) { $(this).data("draggable").originalPosition = {top:0, left:0} $(this).appendTo($(this).data('originalParent')) } return !dropped; }
и это все! Вы можете проверить это, работая здесь:http://jsfiddle.net/eUs3e/1/
примите во внимание, что, если в любом обновлении пользовательского интерфейса jQuery, поведение
revert
илиoriginalPosition
изменения, вам потребуется чтобы обновить код, чтобы заставить его работать. Имейте это в виду.Если вам нужно решение, которое не использует вызовы внутренних интерфейсов.перетаскиваемый, вы можете сделать свой
body
сбрасываемый элемент с определяется какfalse
. Вы должны будете убедиться, что вашbody
элементы занимают весь экран.удачи!
в случае, если кто-то заинтересован, вот мое решение проблемы. Он работает полностью независимо от перетаскиваемых объектов, используя вместо этого события для сбрасываемого объекта. Он работает довольно хорошо:
$(function() { $(".draggable").draggable({ opacity: .4, create: function(){$(this).data('position',$(this).position())}, cursor:'move', start:function(){$(this).stop(true,true)} }); $('.active').droppable({ over: function(event, ui) { $(ui.helper).unbind("mouseup"); }, drop:function(event, ui){ snapToMiddle(ui.draggable,$(this)); }, out:function(event, ui){ $(ui.helper).mouseup(function() { snapToStart(ui.draggable,$(this)); }); } }); }); function snapToMiddle(dragger, target){ var topMove = target.position().top - dragger.data('position').top + (target.outerHeight(true) - dragger.outerHeight(true)) / 2; var leftMove= target.position().left - dragger.data('position').left + (target.outerWidth(true) - dragger.outerWidth(true)) / 2; dragger.animate({top:topMove,left:leftMove},{duration:600,easing:'easeOutBack'}); } function snapToStart(dragger, target){ dragger.animate({top:0,left:0},{duration:600,easing:'easeOutBack'}); }
это связано с revert origin : чтобы установить origin, когда объект перетаскивается : просто используйте
$(this).data("draggable").originalPosition = {top:0, left:0};
например: я использую вот так
drag: function() { var t = $(this); left = parseInt(t.css("left")) * -1; if(left > 0 ){ left = 0; t.draggable( "option", "revert", true ); $(this).data("draggable").originalPosition = {top:0, left:0}; } else t.draggable( "option", "revert", false ); $(".slider-work").css("left", left); }
Я нашел еще один простой способ справиться с этой проблемой, вам просто нужен атрибут "connectToSortable:" для перетаскивания, как показано ниже кода:
$("#a1,#a2").draggable({ connectToSortable: "#b,#a", revert: 'invalid', });
PS: подробнее и пример
как перемещать Перетаскиваемые объекты между исходной областью и целевой областью с помощью jQuery