在droppable的out事件上将jQuery可拖动对象还原回其原始容器

时间:2011-04-20 19:00:30

标签: jquery jquery-ui

我有一个可拖动的项目,如果没有丢弃在droppable中将恢复。这种方法很有效,直到用户删除了droppable中的项目。如果他们认为他们在任何时候犯了一个错误他们将拖拽拉出来就会恢复到掉落状态。我希望在退出并停用拖动时返回其原始容器。

我的代码如下,但我提供了a sample on 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 个答案:

答案 0 :(得分:126)

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

答案 1 :(得分:7)

我不确定这是否适合您的实际使用,但它适用于您的测试用例 - 在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'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);
        }
    });
});

答案 2 :(得分:4)

如果要将元素还原到源位置,如果它没有放在#droppable元素内,只需在脚本开头(而不是位置)保存draggable的原始父元素,并且如果您确认它未被放入#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())
});

在这里,您将拥有可拖动的原始父元素。现在,你必须在一个精确的时刻恢复它的父母。

每次从droppable拖出元素时都会调用

drop,而不是停止。所以,你添加了很多事件回调。这是错误的,因为您永远不会清除mouseup事件。你可以挂钩回调并检查元素是否被#droppable元素内部或外部删除的好地方是revert,你现在正在做,所以,只需删除{{ 1}}回调。

当元素被删除,并且需要知道它是否应该被还原时,您确定在新的拖动开始之前您将不会与用户进行任何其他交互。所以,使用你用来知道它是否应该还原或知道的相同条件,让我们用一段代码替换这个drop:将父元素恢复到原始div,并重置{{1}来自alert内部。 originalPosition属性在draggable时设置,因此,如果更改元素的所有者,则应重置它,以使恢复动画转到正确的位置。所以,让我们将其设置为originalPosition,使动画转到元素的原点:

_mouseStart

就是这样!您可以在此处查看此工作:http://jsfiddle.net/eUs3e/1/

考虑到,如果在任何jQuery的UI更新中,{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; } 的行为发生了变化,您需要更新代码才能使其正常工作。请记住。

如果您需要一个不使用ui.draggable内部调用的解决方案,您可以将revert作为可放置元素,originalPosition选项定义为body 。您必须确保greedy个元素全屏显示。

祝你好运!

答案 3 :(得分:3)

如果有人感兴趣,这是我解决问题的方法。它通过使用Droppable对象上的事件完全独立于Draggable对象。它运作得很好:

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

答案 4 :(得分:1)

它与恢复原点有关:在拖动对象时设置原点:只需使用$(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);
                }

答案 5 :(得分:0)

我找到了另一种简单的方法来解决此问题,您只需要将属性“ connectToSortable:”拖入即可,如以下代码所示:

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

PS:更多细节和示例
How to move Draggable objects between source area and target area with jQuery