jQuery拖放/放置范围问题

时间:2010-06-22 21:36:22

标签: javascript jquery jquery-ui

查看代码here on jsbin.我基本上试图创建一系列开关。每个填充的红色方块都可以上下拖动。底部的红色轮廓是掉落区域。当一个正方形被拖过一个有资格接受它的放置区时,放置区应该变成粉红色。

此代码存在两个问题。一个是当肘节的运动被约束到y轴时,它们仍然可以掉落在任何下落区域上。单击并拖动一个切换按钮并在底行周围滑动,即使切换到位,您也会看到拖放区变为粉红色。

这导致了第二个问题。为了解决这个问题,我尝试使用范围选项,该选项对拖放进行分组。拖动只能放在具有相同范围的放置区域上。在上面的示例中,添加范围的行已注释掉。每次拖放的范围都是“默认”。

如果您取消注释这两行(如果您是jsbin的新手,请点击右上角的标签,然后在更改后点击预览)您会看到,而不是将每个拖动限制为一个放置区域,它们不能任何放置区域的下降时间更长。回调函数永远不会触发。

为方便起见,这里是示例的javascript部分:

$(document).ready( function() {
    var draggables = $('div.dragMe'),
    droppables = $('div.dropMe');

    draggables.draggable(
    {
        axis: 'y',
        containment: 'parent'
    });

    droppables.droppable(
    {
        hoverClass: 'dropped',
        drop: dropCallBack
    });

    draggables.each(function(index) {
        //$(this).draggable('option', 'scope', ''+index);
        //droppables.eq(index).droppable('option', 'scope', ''+index);

        $(this).text( $(this).draggable('option', 'scope') )
        droppables.eq(index).text( droppables.eq(index).droppable('option', 'scope') );
    });

    function dropCallBack(e, ui) {
        alert('Dropped!');
    }
});

1 个答案:

答案 0 :(得分:9)

通过选项功能设置droppable的scope选项时,jQuery中存在一个错误。 jQuery维护一个包含所有已注册sortables的数组(现在我们称之为S),其中每个键都是一个特定的范围。当您将可拖动元素拖放到droppable中时,jQuery会检查draggable的scope属性,并检查您尝试拖放的droppable是否存在于S[scope]中。如果不是,则意味着您要投入的可投放的范围与可拖动的范围不同。

问题是当您通过执行.droppable('option', 'scope', ...)更改范围选项时,数组S不会更新。其他所有内容(据我所见)都已正确更新(实际jQuery对象的选项属性等),导致在通过.droppable('option', 'scope')获取范围选项时返回“正确”结果。

我发现其他几个人有同样的问题并且没有解决方案出现,当我搜索解决方案("jquery droppable scope option")时出现了这个问题,所以我认为提供临时解决方案可能会有用解决方案,直到它被修复。我做了一个扩展函数,关于可能与其他选项冲突的测试不是很好,但至少它是一个开始。 $.ui.ddmanager.droppables是之前调用S的数组。

jQuery.fn.extend({

    setDroppableScope: function(scope) {
        return this.each(function() {
            var currentScope = $(this).droppable("option","scope");
            if (typeof currentScope == "object" && currentScope[0] == this) return true; //continue if this is not droppable

            //Remove from current scope and add to new scope
            var i, droppableArrayObject;
            for(i = 0; i < $.ui.ddmanager.droppables[currentScope].length; i++) {
                var ui_element = $.ui.ddmanager.droppables[currentScope][i].element[0];

                if (this == ui_element) {
                    //Remove from old scope position in jQuery's internal array
                    droppableArrayObject = $.ui.ddmanager.droppables[currentScope].splice(i,1)[0];
                    //Add to new scope
                    $.ui.ddmanager.droppables[scope] = $.ui.ddmanager.droppables[scope] || [];
                    $.ui.ddmanager.droppables[scope].push(droppableArrayObject);
                    //Update the original way via jQuery
                    $(this).droppable("option","scope",scope);
                    break;
                }
            }
        });
    }
});

您的示例将如下所示

draggables.each(function(index) {
    $(this).draggable('option', 'scope', ''+index);
    droppables.eq(index).setDroppableScope(''+index);

    $(this).text( $(this).draggable('option', 'scope') )
    droppables.eq(index).text( droppables.eq(index).droppable('option', 'scope') );
});

Here's the updated jsbin