jQuery UI可拖拽小部件的放置事件触发两次。

16

首先,我知道这个问题以前在这个网站和其他网站上都被问过,但是对于我的情况,答案都很垃圾(如果它们不完全是垃圾),并且(至少对于这个问题:jQuery UI drop event of droppable fires on sortable),建议只是完全关闭.sortable,这肯定不是我想做的。

好的,我有这个jquery代码(请注意,如果任何选项或HTML ID看起来很愚蠢,这只是为了测试,以便我可以尝试弄清楚):

$(function () {
    $("#sortable").sortable({
        revert: true
    });
    $("#draggable, #draggable2").draggable({
        connectToSortable: "#sortable",
        helper: "clone",
        revert: "invalid"
    });

    $("#sortable").droppable({
        drop: function (event, ui) { alert("done been triggered."); }
    });

    $("ul, li").disableSelection();
});

这里是有效的标记:

<div class="objectPaletteHolder">
    <ul>
        <li id="draggable" class="ui-state-highlight">Drag me down</li>
        <li id="draggable2" class="ui-state-highlight">Drag this down, too</li>
        <li id="draggable2" class="ui-state-highlight">Drag this down, also</li>
        <li id="draggable2" class="ui-state-highlight">Drag this down, as well</li>
        <li id="draggable2" class="ui-state-highlight">Drag this down, too</li>
        <li id="draggable2" class="ui-state-highlight">Drag this down, too</li>
        <li id="draggable2" class="ui-state-highlight">Drag this down, too</li>
        <li id="draggable2" class="ui-state-highlight click">Drag this down, click</li>
        <li id="draggable2" class="ui-state-highlight clicky">Drag this down, clicky</li>
    </ul>
</div>
<div class="editContainer">
    <ul id="sortable">
        <li class="ui-state-default">Item 1</li>
        <li class="ui-state-default">Item 2</li>
        <li class="ui-state-default">Item 3</li>
        <li class="ui-state-default">Item 4</li>
        <li class="ui-state-default">Item 5</li>
    </ul>
</div>

我没有重叠的sortable div或类似的东西,我认为我理解这是为什么(因为默认情况下sortable会获取可拖动属性?),但我似乎无法为此做任何事情。

问题,当然,在于...

drop: function (event, ui) { alert("done been triggered."); }

触发两次,只需要一次。

我认为这个问题应该有一个简单的解决方案,如果需要大量复杂的脚本才能解决这个问题,我会觉得这些jQuery小部件不值得麻烦。也许我只是感到困惑?


1
@Itay 根据您的要求:http://jsfiddle.net/dMen8/6/ - VoidKing
3个回答

28

在同一元素上同时使用sortabledroppable会出现已知问题。

您可以使用sortablereceive事件代替。

jsFiddle演示

$("#sortable").sortable({
        revert: true,
        receive: function (event, ui) {      
            alert("receive been triggered.");
        }
}).droppable({ });

哇,这正是我想要的。我在三个不同的小部件中筛选了各种事件,但我想我没有看到“接收”,或者没有想到它适用于我想要的内容。无论如何,(这个答案+你=最棒的)。谢谢,伙计! - VoidKing
酷,刚注意到它附加在可排序的上面,而不是可放置的 :) - Itay
确实。我还注意到你在.sortable之后附加了.droppable({})。这个是可以分开做的吗? - VoidKing
是的,它可以。我只是更喜欢链式编程。 - Itay
太棒了,最后一个问题,考虑到您的偏好,由于我可能以后不容易再问到这个问题。这只是一种偏好,还是有任何实际的连锁效应?出于可读性的考虑,我通常更喜欢另一种方式,但可能还有其他我不知道的缺点。我相信差异并不是很大,只是好奇。 - VoidKing
1
通过链式调用,您可以避免再次调用 $("#sortable")。这样就少了一个函数调用,因此效率会稍微提高一些。如果我没记错的话,您可以缓存这个对象($sortable = $("#sortable")),并使用这个变量,这样 getElementById 就不会被反复调用。这篇文章可能会有所帮助:jQuery 链式调用快速指南 - Itay

2
我遇到了类似的问题。有两个可放置元素,其中一个具有相对位置,另一个具有绝对位置。它们没有嵌套,但是具有绝对位置的部分在具有相对位置的部分上方(在jQuery文档中称为“相交”)。当我将可拖动的元素移动到“绝对”可放置元素时,会触发两次drop事件。我已经搜索了几天,但没有找到任何解决方法。
然后我决定制作一个简单的通用解决方法。看起来并不是很吸引人,但这将帮助解决任何触发2个drop事件的情况。
drop: function( e, ui ) {
    if ( ! $('.already-dropped').length ) {
        $('body').addClass('already-dropped');
        setTimeout( function() {
            $('.already-dropped').removeClass('already-dropped');
        }, 100 );
        // callback code...
    }
}

-2
也许我有点晚了,但我希望这篇文章能帮助到某些人。这是我使用的代码。基本上,如果函数被调用两次,它们之间的时间间隔应该很快(比人类通常做的更快),所以我将数字设置为200毫秒。
我使用localStorage来设置一个名为“last_call”的变量。它是函数被调用的时间。在下一次调用中,我们将检查函数是否先前被调用过。如果没有被调用,函数将继续执行。如果已经被调用,我们将检查上次调用的时间。如果在200毫秒内调用了它(显然是机器调用,而不是人类调用),我们将不再调用它。
    var d = new Date();
    var this_time = d.getTime();
    if ( localStorage.getItem("last_call") != null)
    {
        if ((this_time - parseInt(localStorage.getItem("last_call"))) < 100)
        {

            return;
        }

    }
    localStorage.setItem("last_call", this_time);

@codingpuss,基本上是因为它看起来像自己疯狂实现的setTimeout()。但即使使用setTimeout(),它也只是一个hack而不是一个整洁的解决方案。 - walv

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