问题 jQuery Draggable + Sortable - 如何拒绝掉入排序?


我有一个可排序的视频列表和一组可拖动的视频。基本上我想确保拖入的视频不在视频的前5分钟内。由于视频长度不同,我想在下降时测试一下 - 加起来直到那时为止,如果不是5分钟还原并显示错误。

我已经尝试连接所有可拖动和可排序的回调(包括未记录的恢复回调)来进行我的测试,但无论我尝试什么,dom总是被改变(并且可排序调用它的更新回调)......

有没有人有什么建议?


3527
2017-08-19 16:57


起源



答案:


您可以通过调用来恢复拖动操作 cancel 的方法 拖动 小部件(该方法未记录,但其名称不以下划线开头,这可以说使其“更安全”可靠地使用)。它只适用于 start 但是,由于其他事件发生得太晚而无法触发恢复动画。

但是,那 排序 即使拖动操作被取消,小部件仍会注册掉落,因此您还必须删除新添加的项目(在此期间) stop 事件,作为 start 事件发生得太早):

$("#yourSortable").sortable({
    start: function(event, ui) {
        if (!canDropThatVideo(ui.item)) {
            ui.sender.draggable("cancel");
        }
    },
    stop: function(event, ui) {
        if (!canDropThatVideo(ui.item)) {
            ui.item.remove();
            // Show an error...
        }
    }
});

你可以看到结果 这个小提琴 (第四项将始终还原)。

更新: 正如John Kurlak在评论中正确指出的那样,该项目因为调用而无法恢复 draggable("cancel"), 但是因为 ui.sender 是 null 在我们的情况下。抛出任何东西都会导致相同的行为。

唉,我试过的所有其他组合导致项目在没有动画的情况下被还原,所以我们最好的选择是避免访问 ui.sender 而是写下这样的东西:

start: function(event, ui) {
    if (!canDropThatVideo(ui.item)) {
        throw "cancel";
    }
}

但是,未捕获的异常仍会出现在控制台中。


10
2017-08-19 19:31



嘿谢谢你的回答!我努力让它工作 - 测试(canDropThatVideo)需要找到它在列表中被删除的位置,以便它可以与相邻的视频进行比较。我尝试过类似的方法:// get adjacent vids var nextVid = $(ui.item).next(); var prevVid = $(ui.item).prev();但这些似乎没有得到正确的 - 可能是因为它在开始事件中...应该有用吗? - lopsided
@ user612911,它更复杂但它可以工作。你必须绑定到 sort 事件而不是 start 并使用 ui.placeholder.next() 和 ui.placeholder.prev(), 分别。你也可能必须记住你对这个项目做出的决定(也许是 data()),为了 stop 处理程序知道该怎么做。 (顺便说一句,你不需要打电话 $() 在...上 ui 成员:他们已经是jQuery对象。) - Frédéric Hamidi
太好了,我现在工作得很好。我还附上了一些逻辑 startdraggable的事件将一些'cantDropHere'类添加到无效的drop空格元素,然后从sortable中排除这些类。谢谢! - lopsided
ui.sender 在您的代码示例和JSFiddle中似乎是null ...我认为当元素来自可拖动而不是另一个可排序时它是null。 - John Kurlak
@FrédéricHamidi它有效,但错误仍在被抛出。我认为当发生错误时,draggable会取消事件(或者某些代码不执行,允许它被放置)。我将检查jQuery源代码。你可以轻松更换 ui.sender.draggable("cancel"); 同 blah 它仍然有效。 - John Kurlak


答案:


您可以通过调用来恢复拖动操作 cancel 的方法 拖动 小部件(该方法未记录,但其名称不以下划线开头,这可以说使其“更安全”可靠地使用)。它只适用于 start 但是,由于其他事件发生得太晚而无法触发恢复动画。

但是,那 排序 即使拖动操作被取消,小部件仍会注册掉落,因此您还必须删除新添加的项目(在此期间) stop 事件,作为 start 事件发生得太早):

$("#yourSortable").sortable({
    start: function(event, ui) {
        if (!canDropThatVideo(ui.item)) {
            ui.sender.draggable("cancel");
        }
    },
    stop: function(event, ui) {
        if (!canDropThatVideo(ui.item)) {
            ui.item.remove();
            // Show an error...
        }
    }
});

你可以看到结果 这个小提琴 (第四项将始终还原)。

更新: 正如John Kurlak在评论中正确指出的那样,该项目因为调用而无法恢复 draggable("cancel"), 但是因为 ui.sender 是 null 在我们的情况下。抛出任何东西都会导致相同的行为。

唉,我试过的所有其他组合导致项目在没有动画的情况下被还原,所以我们最好的选择是避免访问 ui.sender 而是写下这样的东西:

start: function(event, ui) {
    if (!canDropThatVideo(ui.item)) {
        throw "cancel";
    }
}

但是,未捕获的异常仍会出现在控制台中。


10
2017-08-19 19:31



嘿谢谢你的回答!我努力让它工作 - 测试(canDropThatVideo)需要找到它在列表中被删除的位置,以便它可以与相邻的视频进行比较。我尝试过类似的方法:// get adjacent vids var nextVid = $(ui.item).next(); var prevVid = $(ui.item).prev();但这些似乎没有得到正确的 - 可能是因为它在开始事件中...应该有用吗? - lopsided
@ user612911,它更复杂但它可以工作。你必须绑定到 sort 事件而不是 start 并使用 ui.placeholder.next() 和 ui.placeholder.prev(), 分别。你也可能必须记住你对这个项目做出的决定(也许是 data()),为了 stop 处理程序知道该怎么做。 (顺便说一句,你不需要打电话 $() 在...上 ui 成员:他们已经是jQuery对象。) - Frédéric Hamidi
太好了,我现在工作得很好。我还附上了一些逻辑 startdraggable的事件将一些'cantDropHere'类添加到无效的drop空格元素,然后从sortable中排除这些类。谢谢! - lopsided
ui.sender 在您的代码示例和JSFiddle中似乎是null ...我认为当元素来自可拖动而不是另一个可排序时它是null。 - John Kurlak
@FrédéricHamidi它有效,但错误仍在被抛出。我认为当发生错误时,draggable会取消事件(或者某些代码不执行,允许它被放置)。我将检查jQuery源代码。你可以轻松更换 ui.sender.draggable("cancel"); 同 blah 它仍然有效。 - John Kurlak


我发现了一种不同的方式。如果你不介意没有它的动画浮动到它的原始位置,你可以随时使用它

.droppable({
    drop: function (event, ui) {

        var canDrop = false;

        //if you need more calculations for
        //validation, like me, put them here

        if (/*your validation here*/)
            canDrop = true;

        if (!canDrop) {
            ui.draggable.remove();
        }
        else{
            //you can put whatever else you need here
            //in case you needed the drop anyway
        }
    }
}).sortable({
    //your choice of sortable options
});

我用这个是因为我需要掉落事件。


3
2018-04-01 11:12