【问题标题】:Revert a jQuery draggable object back to its original container on out event of droppable在 droppable 的 out 事件中将 jQuery 可拖动对象恢复到其原始容器
【发布时间】:2011-04-20 19:00:30
【问题描述】:

我有一个可拖动的项目,如果不放在 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 };
            });
        }
    });
});

【问题讨论】:

  • Unfortunately, for my purposes out fires too soon (the moment the draggable leaves.) 这不正是out 的目的吗?您是否只想知道他们是否mouseupout
  • @drachenstern 好主意。我将在 out 事件中进行试验,但无论哪种方式都不能解决可拖动恢复为可放置的问题。
  • 很高兴我能提供帮助,但仍然不确定我在你的脑海中触发了什么。我认为,一旦你移动它,draggable 就会失去它的“home”droppable。您可能需要将该信息存储在某个辅助方法中。
  • @drachenstern 我打算存储原始位置。我只是无法让它使用它而不是它在可放置中的新位置。 :( 顺便说一句:代码已更新以反映您的好建议。
  • 您需要两个可放置的区域。当你没有超过任何一个,并且你返回!dropped,那是你需要处理下降到哪里的时候。不要在 out 或 mouseup 上执行此操作。一旦你放在可放置区域上,它就没有任何地方可以放置还原了。 (或者,当您没有检测到您在可放置区域上方时,只需删除“位置:相对”)

标签: jquery jquery-ui


【解决方案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();
});

【讨论】:

  • 感谢您添加此解决方案。它工作得很好。想知道是否有人可以解释它的详细信息?
  • @leetou:我已经更新了代码并在演示站点上添加了破解说明。 ;)
  • 感谢您为 jQuery 1.9 更新此内容! :)
  • 同上,感谢更新版本,以及对代码的有用解释。
  • 演示链接失效
【解决方案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'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);
        }
    });
});

【讨论】:

  • 这是我需要的。谢谢
【解决方案3】:

如果你想将元素恢复到源位置(如果它没有放在#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 回调。

当元素被放下,并且需要知道它是否应该被恢复时,你肯定知道在新的拖动开始之前你不会有来自用户的任何其他交互。所以,使用你用来知道它是否应该恢复或知道的相同条件,让我们用一段代码替换这个alert:将父元素恢复到原始div,并从@重置originalPosition 987654334@ 内部。 originalPosition 属性是在_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 的 UI 更新中,revertoriginalPosition 的行为发生变化,您需要更新代码才能使其正常工作。请记住这一点。

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

祝你好运!

【讨论】:

  • Gonzalo,我认为这里不需要“originalParent”逻辑。当你放下一个可拖动对象时,底层的 DOM 结构实际上并没有改变。
  • 是的!你说得对。没有必要 :-) 我习惯于使用 UL 和 LI 来处理可拖动/可放置的内容。谢谢!
  • 你在这里拥有的东西肯定是有效的,但是如果与无序列表一起使用,readd 会有点生涩。通过附加它跳到底部。也就是说,这是更具可读性的解决方案。据我所知,drop 仅在实际删除元素时才被调用。我错过了什么吗?
  • @ahsteele 也许您可以提供您正在尝试使用的实际 DOM。它可能会帮助我们为您提供更好的解决方案。
【解决方案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】:

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

    【讨论】:

      【解决方案6】:

      我找到了另一种简单的方法来处理这个问题,你只需要属性“connectToSortable:”就可以像下面的代码一样拖动:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-22
        • 1970-01-01
        相关资源
        最近更新 更多