Верните объект перетаскивания jQuery обратно в исходный контейнер на событие droppable
У меня есть перетаскиваемый элемент, который, если не упадет в droppable, вернется. Это хорошо работает, пока пользователь не опустит элемент в раскрывающемся списке. Если они решат, что совершили ошибку в любое время, когда они вытащили перетащив, она вернется к droppable. Я бы предпочел, чтобы выключение и деактивация draggable возвращается в исходный контейнер.
Мой код ниже, но я предоставил образец в 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 };
});
}
});
});
Ответы
Ответ 1
$(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();
});
Ответ 2
Я не уверен, что это будет работать для вашего фактического использования, но оно работает в вашем тестовом примере - обновлено на http://jsfiddle.net/sTD8y/27/.
Я просто сделал это так, чтобы встроенный возврат использовался, только если элемент не был отброшен раньше. Если он был сброшен, возврат выполняется вручную. Вы можете настроить это, чтобы оживить какое-то вычисленное смещение, проверив фактические свойства 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 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);
}
});
});
Ответ 3
Если вы хотите вернуть элемент в исходную позицию, если он не выпал внутри элемента #droppable
, просто сохраните исходный родительский элемент перетаскиваемого в начале script (вместо позиции) и если вы убедитесь, что он не упал в #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
устанавливается во время _mouseStart
, поэтому, если вы меняете владельца элемента, вы должны reset его, чтобы анимация возврата вернулась в нужное место. Таким образом, установите значение {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
изменяется, вам необходимо обновить код, чтобы он работал. Имейте в виду, что.
Если вам нужно решение, которое не использует вызовы внутренних элементов ui.draggable, вы можете сделать свой body
элемент с возможностью удаления с greedy
опцией, определенной как false
. Вам нужно будет убедиться, что ваши элементы body
будут отображаться в полноэкранном режиме.
Удачи!
Ответ 4
В случае, если кому-то интересно, вот мое решение проблемы. Он полностью работает независимо от объектов Draggable, вместо этого использует события в объекте Droppable. Он работает достаточно хорошо:
$(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'});
}
Ответ 5
Это связано с возвратным началом: установить начало координат, когда объект перетаскивается: просто используйте $(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);
}