Ripristina un object trascinabile jQuery nel suo contenitore originale in caso di evento trascinabile

Ho un object trascinabile che se non lasciato cadere in un droppabile verrà ripristinato. Funziona bene fino a quando un utente non rilascia un object nel droppable. Se decidono di aver commesso un errore ogni volta che estraggono il dispositivo, esso ritorna all’eliminabile. Preferirei che fuori e distriggersre il draggable ritorna al suo contenitore originale.

Il mio codice è sotto, ma ho fornito un esempio su jsFiddle .

HTML

I revert when I'm not dropped

Drop me here

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 }; }); } }); }); 

 $(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(); }); 

Non sono sicuro che funzioni per il tuo uso effettivo, ma funziona nel tuo caso di test, aggiornato all’indirizzo http://jsfiddle.net/sTD8y/27/ .

L’ho appena fatto in modo che il ripristino incorporato venga utilizzato solo se l’articolo non è stato eliminato prima. Se è stato eliminato, il ripristino viene eseguito manualmente. Puoi regolarlo per animare un certo offset calcolato controllando le effettive proprietà CSS, ma ti lascio giocare con questo perché molto dipende dal CSS del trascinabile e sta circondando la struttura del 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); } }); }); 

Se si desidera ripristinare l’elemento nella posizione sorgente se non viene rilasciato all’interno di un elemento #droppable , è sufficiente salvare l’elemento padre originale del trascinamento all’inizio dello script (anziché della posizione) e verificare che non sia #droppable in #droppable , quindi basta ripristinare il genitore di #draggable su questo elemento originale.

Quindi, sostituisci questo:

 }).each(function() { var top = $(this).position().top; var left = $(this).position().left; $(this).data('orgTop', top); $(this).data('orgLeft', left); }); 

con questo:

 }).each(function() { $(this).data('originalParent', $(this).parent()) }); 

Qui, avrai l’elemento genitore originale del trascinabile. Ora devi ripristinare il genitore in un preciso momento.

drop viene chiamato ogni volta che l’elemento viene trascinato fuori dalla droppable, non alla fermata. Quindi, stai aggiungendo molte callback di eventi. Questo è sbagliato, perché non si pulisce mai l’evento mouseup . Un buon posto in cui è ansible agganciare una richiamata e controllare se l’elemento è stato rilasciato all’interno o all’esterno dell’elemento #droppable , viene revert e lo stai facendo proprio ora, quindi elimina semplicemente la richiamata di drop .

Quando l’elemento viene eliminato e deve sapere se deve essere ripristinato o meno, si è sicuri che non si avranno altre interazioni da parte dell’utente fino all’avvio successivo del trascinamento. Quindi, usando la stessa condizione che stai usando per sapere se deve essere ripristinata o conosciuta, sostituiamo questo alert con un frammento di codice che: ripristina l’elemento genitore al div originale e reimposta la posizione originalPosition dagli interni draggable . La proprietà originalPosition viene impostata al momento di _mouseStart , quindi, se si modifica il proprietario dell’elemento, è necessario ripristinarlo, in modo da rendere l’animazione di ripristino andare nella posizione corretta. Quindi, impostiamo su {top: 0, left: 0} , facendo andare l’animazione al punto di origine dell’elemento:

 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; } 

E questo è tutto! Puoi controllare questo funzionando qui: http://jsfiddle.net/eUs3e/1/

Prendi in considerazione che, se in qualsiasi aggiornamento dell’interfaccia utente di jQuery, il comportamento di revert o modifica di originalPosition , è necessario aggiornare il codice per farlo funzionare. Tieni presente che.

Se hai bisogno di una soluzione che non faccia uso delle chiamate interne di ui.draggable, puoi rendere il tuo body un elemento trascinabile con un’opzione greedy definita come false . Dovrai assicurarti che gli elementi del tuo body occupino tutto lo schermo.

In bocca al lupo!

Nel caso qualcuno sia interessato, ecco la mia soluzione al problema. Funziona completamente indipendentemente dagli oggetti trascinabili, utilizzando invece gli eventi sull’object Droppable. Funziona abbastanza bene:

 $(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'}); } 

È relativo al ripristino dell’origine: per impostare l’origine quando l’object è trascinato: basta usare $(this).data("draggable").originalPosition = {top:0, left:0};

Ad esempio: io uso in questo modo

  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); } 

Ho trovato un altro modo semplice per affrontare questo problema, è sufficiente l’attributo “connectToSortable:” per trascinarlo come nel codice seguente:

 $("#a1,#a2").draggable({ connectToSortable: "#b,#a", revert: 'invalid', }); 

PS: maggiori dettagli ed esempi
Come spostare oggetti trascinabili tra l’area di origine e l’area di destinazione con jQuery