JQuery UI 可拖放,具有多个作用域

JQuery UI Drag/Droppable with multiple scopes?

本文关键字:作用域 UI 拖放 JQuery      更新时间:2023-09-26

我想要几个可拖动对象类,每个类对应于一类可拖放对象。但除此之外,我还想有一个单独的"垃圾箱",在那里可以放下所有可拖动物,直到找到适合它们的可拖拽物。

现在,这可以通过接受功能轻松实现。但是,我最多可能有 20 个类,每个类都有 30-40 个可拖动/可放置对象。因此,如果我为此使用"接受"功能,当我拿起可拖动的那一刻,我的 chrome 会冻结,因为它会为屏幕上的每个可拖放内容运行测试:(

如果我使用"scope"属性,这可以解决,因为它似乎使用了某种不同的方式。但是,当我使用范围时,我似乎无法实现"垃圾箱"概念,因为它只能有一个范围!

有没有办法绕过这个问题?给可拖动对象多个范围,还是给垃圾箱多个范围?或者也许我想不出其他解决方案?

在内部,只要您开始拖动draggable,jQuery UI 就会运行以下代码,以确定哪些droppable有资格接收draggable

var m = $.ui.ddmanager.droppables[t.options.scope] || [];
var type = event ? event.type : null; // workaround for #2317
var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();
droppablesLoop: for (var i = 0; i < m.length; i++) {
    if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue;   //No disabled and non-accepted
    for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item
    m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue;                                   //If the element is not visible, continue
    if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
    m[i].offset = m[i].element.offset();
    m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
}

如您所见,代码并非易事,并且可以解释为什么每次开始拖动时都会看到性能降低。

需要注意的一件事是,droppablesLoop中检查的第一件事是droppable是否被禁用。

因此,为了提高性能,您可以随时手动禁用相应的droppable小部件,这将使您快速跳出上面的代码块。 您可以通过在 draggable 上使用 start 事件来执行此操作,该事件将首先触发。

$('.draggable').draggable({
    start: function() {
        $('.invalid-droppable-elements').droppable('option', 'disabled', true);
    },
    stop: function() {
        $('.invalid-droppable-elements').droppable('option', 'disabled', false);
    }
});

这实质上使您自己实现accept/scope逻辑,性能影响取决于您的算法。 不过,实施起来应该不会那么糟糕。 插件之所以如此缓慢,是因为它们必须处理许多不同的情况。

jQuery UI 不支持向单个 draggable/droppable 元素添加多个范围,但您可以自行推出该功能。

我举了一个例子来展示这一点 - http://jsfiddle.net/tj_vantoll/TgQTP/1/。