jQuery拖放-检查是否在可放置区域外被放置

39

如果这个问题已经在另一个问题中得到了回答,我很抱歉,但我没有找到与我的问题相关的答案!

我正在尝试测试一个jQuery可拖动元素是否被放置在不合法的放置目标之外。通常情况下,可以通过还原可拖动元素来解决90%的问题,但我不想这样做。相反,如果可拖动元素被放置在放置目标上,我想执行一件事情(运行良好!),如果它被放置在所有可能的放置目标之外,则执行其他操作(目前让我感到困扰!)。

简而言之:

jQuery('#droppable').droppable(
{
    accept: '#draggable',
    drop: function(event, ui)
    {
        // awesome code that works and handles successful drops...
    }
});

jQuery('#draggable').draggable(
{
    revert: false,
    stop: function()
    {
        // need some way to check to see if this draggable has been dropped
        // successfully or not on an appropriate droppable...
        // I wish I could comment out my headache here like this too...
    }
});

我觉得我可能忽略了一些非常明显的东西...提前感谢任何帮助!

7个回答

57

由于 droppable 的 drop 事件在 draggable 的 stop 事件之前触发,所以我认为你可以在 drop 事件中对被拖动的元素设置标志,像这样:

jQuery('#droppable').droppable(
{
    accept: '#draggable',
    drop: function(event, ui)
    {
        ui.helper.data('dropped', true);
        // awesome code that works and handles successful drops...
    }
});

jQuery('#draggable').draggable(
{
    revert: false,
    start: function(event, ui) {
        ui.helper.data('dropped', false);
    },
    stop: function(event, ui)
    {
        alert('stop: dropped=' + ui.helper.data('dropped'));
        // Check value of ui.helper.data('dropped') and handle accordingly...
    }
});

太神奇了,但是:有没有关于.data的文档?对我来说,它就像从天而降一样 :3(读作:找不到更多信息) - nuala
4
第6行的 ui.draggable.data('dropped', true); 应该改为 ui.helper.data('dropped', true);,是吗? - maryisdead
我认为是这样。否则就一直是错误的。 :) - Drachenfels

9

我看到你已经得到了答案;无论如何,今天我遇到了同样的问题,我是这样解决的:

var outside = 0;

// this one control if the draggable is outside the droppable area
$('#droppable').droppable({
    accept      : '.draggable',
    out         : function(){
        outside = 1;
    },
    over        : function(){
        outside = 0;
    }
});

// this one control if the draggable is dropped
$('body').droppable({
    accept      : '.draggable',
    drop        : function(event, ui){
        if(outside == 1){
            alert('Dropped outside!');
        }else{
            alert('Dropped inside!');
        }
    }
});

我需要这个是因为我无法更改我的可拖动选项,所以我只能使用可放置物(我需要在 FullCalendar 插件中使用它)。我想,使用“贪婪”选项的可放置物可能会有一些问题,但在大多数情况下应该可以工作。
PS:对我的糟糕英语感到抱歉。
编辑:如建议的那样,我创建了使用 jQuery.data 的版本;可以在这里找到:jsfiddle.net/Polmonite/WZma9/ 无论如何,jQuery.data 文档说:
请注意,此方法目前不支持在 XML 文档上设置数据的跨平台支持,因为 Internet Explorer 不允许通过扩展属性附加数据。
(这意味着在 IE 8 之前无法使用它) 编辑2:正如@Darin Peterson所指出的那样,前面的代码不能与多个放置区一起使用;这应该解决这个问题:http://jsfiddle.net/Polmonite/XJCmM/ 编辑3:编辑2中的示例有一个错误。如果我将"Drag me!"拖到底部的可放置区域,然后将"Drag me too"放到上方的可放置区域,然后将"Drag me too"放到外面,它会提示"Dropped inside!"。因此,请不要使用它。 编辑4:正如@Aleksey Gor所指出的那样,编辑2中的示例是错误的;实际上,它更像是一个解释如何循环遍历所有可拖动/可放置项的示例,但我实际上忘记删除警报消息,所以它非常令人困惑。这里是更新的fiddle。

很好而且简单!这是一个不错的解决方案,特别是当您无法访问可拖动对象时。我正在思考可能的作用域问题,想知道是否可以使用 $("#droppable").data("outside", true); 更优雅地 '携带' 变量状态?不过还是很好的解决方案!谢谢您的意见! :) - Chris Kempen
1
当然。我已经在答案中使用jQuery.data添加了版本;无论如何,这意味着没有IE7(如果有人在乎的话)。 - Polmonite
太棒了!感谢你的研究和详细的回答!点赞! - Chris Kempen
如果您有多个可放置位置,则此解决方案将无法正常工作。例如,我目前正在处理的页面具有许多可放置单元格,当您的可拖动对象位于一个可放置单元格上并转移到另一个也是可放置的单元格时,会触发“out”事件。请注意,仅因为触发了“out”事件并不一定意味着您所在的区域不可放置。 - Darin Peterson
@Darin Peterson:没错。无论如何,可以通过循环遍历放置区域并查找每个 .data('outside') 来轻松解决问题,就像这样:http://jsfiddle.net/Polmonite/XJCmM/。 - Polmonite

4
尝试使用“out”事件来处理一个可拖动元素。这是相关技术文档的链接:documentation
当接受的可拖动元素被拖出(在容差范围内)此可放置区域时,将触发该事件。如果我没理解错,这就是您需要的功能。还有一种可能性是创建一个覆盖整个页面的元素。如果将元素放置在其中,您可以触发事件。虽然不是最好的方法,但我认为这是唯一的解决方案。因为您需要其他的“可放置”项来触发这些事件。

嘿ggzone,感谢您的快速回复...如果我拖动的可拖动对象来自有效的可放置区域,那就太完美了。如果一个可拖动对象从其原始位置被拖动,然后随意放置在远离合法可放置区域的地方,那么据我所知,此事件将永远不会被触发! - Chris Kempen
太棒了,谢谢ggzone...像你说的那样,这可能不是最好的选择,如果你还没有看到Luke提供的答案,我认为它提供了一个更优雅的解决方案,而且结果相同! - Chris Kempen

2
以下示例的优点在于,您不需要更改或了解可放置代码:
可拖动的 revert 属性可以是一个函数(value){}。会传递一个值作为参数,指示助手是否被放置到元素(即放置元素)上,或者如果没有放置到元素上(放置在外部或未被接受),则为“false”。
注意:您需要从还原函数中返回正确的 bool 值,以告诉助手是否还原或不还原(true/false)。True 表示是,将助手通过缓慢移回原始位置(开箱即用);False 表示不是,只需突然删除助手。将 revert 属性设置为“invalid”是说“是的,如果放在外面,则还原辅助程序”和“否,如果放在可放置元素上并被接受,则立即杀死辅助程序”的快捷方式。
我的猜测是,您可以在开始事件期间使用数据属性将当前 UI 助手添加到可拖动容器中。然后在还原函数中从数据属性中取出它。然后向助手添加一个属性,指示它是否已被删除。最后,在停止事件中,检查此数据属性值,并执行您想要的操作。

可拖动对象的事件/函数调用顺序为:开始-还原-停止

以下是一个示例:

jQuery('#draggable').draggable(
{
    start: function(event, ui) {
        $(this).data('uihelper', ui.helper);
    },
    revert: function(value){
        var uiHelper = (this).data('uihelper');
        uiHelper.data('dropped', value !== false);
        if(value === false){
             return true;
        }
        return false;
    },
    stop: function(event, ui)
    {
        if(ui.helper.data('dropped') === true){
            // handle accordingly...
        }
    }
});

你甚至可以在 revert 函数中返回 true,并在停止事件期间根据 data('dropped') 值使用 ui.helper.remove() 删除 helper。 或者,如果你仍然度过糟糕的一天,你甚至可以使用 CSS3 将其爆炸 ;)


0

我添加了我采用的解决方案,因为您可以从移动对象的CSS类非常容易地理解它:

jQuery('#draggable').draggable({
  stop: function(event, ui) {
    if (ui.helper.hasClass('ui-draggable-dragging')) {
      console.log('dropped out');
    } else {
      console.log('dropped successfully');
    }
  }
});

0

这对我有用:

<script>
$( function() {
    $( "#draggable" ).draggable();
    $( ".droppable" ).droppable({
        drop: function( event, ui ) {
            if( $(this) ){
                $( "#draggable" ).draggable( "disable" );
            }                
        },
    });
} );

0

旧问题和旧答案意味着这可能是一个新的解决方案。正如问题所述,您(也许)想知道是否将可拖动项放在了不可放置区域。对于我来说,在至少95%的情况下,我并不真的关心是否,我只希望当发生这种情况时,事情能够回到之前没有任何更改的状态。

revert设置为字符串invalid可以实现所需的行为,而无需进行任何额外的代码或花哨的操作。

$( '#draggable' ).draggable({
    revert: "invalid",
    stop: function( event, ui )
    {
       // whatever
    }
});

它不会告诉你“是否在可放置区域之外被丢弃了”,但如果发生这种情况,它将恢复到初始状态。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接