在Dropable事件发生时,将jQuery可拖动对象还原回其原始容器

在Dropable事件发生时,将jQuery可拖动对象还原回其原始容器,jquery,jquery-ui,Jquery,Jquery Ui,我有一个可拖放的项目,如果不在一个可拖放将恢复。在用户将一个项目放入可拖放列表之前,这项功能一直运行良好。如果他们决定在任何时候拉出可拖动设备时犯了错误,它将恢复为可拖放设备。我更喜欢打开并停用Dragable,使其返回到原始容器 我的代码如下,但我已提供 HTML 我不确定这是否适用于您的实际使用,但它适用于您的测试用例-更新于 我只是这样做的,只有在项目之前没有被删除的情况下才使用内置的恢复。如果已删除,则手动执行还原。您可以通过检查实际的CSS属性来调整它,使其动画化到某个计算出的偏移量,

我有一个可拖放的项目,如果不在一个可拖放将恢复。在用户将一个项目放入可拖放列表之前,这项功能一直运行良好。如果他们决定在任何时候拉出可拖动设备时犯了错误,它将恢复为可拖放设备。我更喜欢打开并停用Dragable,使其返回到原始容器

我的代码如下,但我已提供

HTML


我不确定这是否适用于您的实际使用,但它适用于您的测试用例-更新于

我只是这样做的,只有在项目之前没有被删除的情况下才使用内置的恢复。如果已删除,则手动执行还原。您可以通过检查实际的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
在每次从可拖放项中拖出元素时调用,而不是在停止时调用。因此,您添加了很多事件回调。这是错误的,因为您从未清除
mouseup
事件。您可以挂接回调并检查元素是否在
#droppable
元素的内部或外部放置的一个好位置是
revert
,您现在正在执行此操作,因此,只需删除
drop
回调即可

当元素被拖放,并且需要知道它是否应该被还原时,您可以肯定地知道,在新的拖放开始之前,用户不会进行任何其他交互。因此,使用您用来知道它是否应该恢复或知道的相同条件,让我们将此
警报
替换为一段代码:将父元素恢复到原始div,并从
可拖动的内部重置
原始位置
原始位置
属性是在
\u mouseStart
时设置的,因此,如果更改元素的所有者,则应重置它,以使“还原”的动画转到正确的位置。因此,让我们将其设置为
{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;
}
就这样!您可以在此处检查此工作:

考虑到,如果在任何jQuery的UI更新中,
revert
originalPosition
的行为发生了变化,则需要更新代码以使其正常工作。记住这一点

如果您需要一个不使用对ui.draggable内部调用的解决方案,您可以使用定义为
false
greedy
选项,使您的
body
成为可拖放元素。你必须确保你的
主体
元素占据全屏

祝你好运

  • 使用jquery 1.11.3jquery ui 1.11.4进行测试

  • 演示:


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

如果有人感兴趣,这是我对这个问题的解决方案。它完全独立于可拖动对象工作,而是使用可拖放对象上的事件。它工作得相当好:

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

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

$("#a1,#a2").draggable({
        connectToSortable: "#b,#a",
        revert: 'invalid',
    });
PS:更多细节和示例

不幸的是,出于我的目的,out启动得太早了(拖拉机离开的那一刻)。
这不是
out的目的吗?你只想知道他们是不是
mouseup
out
?@drachenstern好主意。我将在out事件中进行实验,但无论哪种方法都无法解决可拖动设备恢复为可拖放设备的问题。很高兴我能提供帮助,但仍然不确定我在您的脑海中触发了什么。我认为,一旦你移动它,拖拽装置就失去了它的“家”可放下性。您可能需要将该信息存储在某个辅助方法中。@drachenstern我正打算存储原始位置。我只是不能让它用它来代替它在下拉列表中的新位置(顺便说一句:代码已更新以反映您的建议。您需要两个可拖放区域。当您未超过其中任何一个区域时,返回
!drop
,此时您需要处理拖放到何处。不要在out或mouseup上执行此操作。一旦您将还原的内容拖放到可拖放区域,它就没有任何地方可以放置。(或者,当你没有检测到你在可拖放区域时,只需删除“position:relative”(位置:相对)Gonzalo,我认为这里不需要“originalParent”逻辑。当你拖放一个可拖放对象时,底层DOM结构实际上不会改变。是的!你是对的。不需要:-)我习惯于使用ULs和LIs来处理可拖动/可拖放。谢谢!这里的内容确实有效,但是如果与无序列表一起使用,readd会有点不稳定。通过将其添加到底部。这意味着这是更可读的解决方案。据我所知,
drop
仅在元素实际被删除时才被调用。我遗漏了什么吗?@ahsteele也许你可以提供你正在尝试使用的实际DOM。它可能是h
               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);
                }
$(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'});
}
$("#a1,#a2").draggable({
        connectToSortable: "#b,#a",
        revert: 'invalid',
    });