jQuery UI可排序容差选项无法按预期工作

时间:2012-05-17 13:54:46

标签: jquery jquery-ui jquery-ui-sortable

以下是tolerance选项的part from jQuery UI documentation

  

这是重新排序在拖动过程中的行为方式。可能的值:   '相交','指针'。在某些设置中,“指针”更自然。

     

intersect:draggable与droppable重叠至少50%

默认值为intersect,但如果鼠标指针不在可排序项目之上,则排序不会发生,无论拖动元素是否比其他可排序项目至少高50%(我期望的功能) )这也发生在演示页面上(上面链接)

这是jQuery UI中的错误,还是我理解错了?

6 个答案:

答案 0 :(得分:24)

对于那些有同样问题的人,我使用的解决方法是:

$('#sortable').sortable({
    axis: 'x',
    sort: function (event, ui) {
        var that = $(this),
            w = ui.helper.outerWidth();
        that.children().each(function () {
            if ($(this).hasClass('ui-sortable-helper') || $(this).hasClass('ui-sortable-placeholder')) 
                return true;
            // If overlap is more than half of the dragged item
            var dist = Math.abs(ui.position.left - $(this).position().left),
                before = ui.position.left > $(this).position().left;
            if ((w - dist) > (w / 2) && (dist < w)) {
                if (before)
                    $('.ui-sortable-placeholder', that).insertBefore($(this));
                else
                    $('.ui-sortable-placeholder', that).insertAfter($(this));
                return false;
            }
        });
    },
});​

适用于水平排序,适用于从outerWidthouterHeightposition.leftposition.top的垂直变化。

Here's a complete working example

答案 1 :(得分:5)

我的可排序项目大小不均匀,这会让事情变得更糟。我已经修改了dioslaska的代码,一旦处理程序的底部通过了孩子的底部(向下移动时)就更改了顺序,并且顶部也是如此...

sort: function (event, ui) {
    var that = $(this),
        draggedHeight = ui.helper.outerHeight(),
        originalTop = ui.originalPosition.top,
        draggedTop = ui.helper.position().top,
        draggedBottom = draggedTop + draggedHeight;
    that.children().each(function () {
        if ($(this).hasClass('ui-sortable-helper') || $(this).hasClass('ui-sortable-placeholder')) {
            return true;
        }
        var childTop = $(this).position().top,
            childHeight = $(this).outerHeight(),
            childBottom = childTop + childHeight,
            isChildAfter = originalTop < childTop,
            largeTop,largeBottom,smallTop,smallBottom;
        if (childHeight > draggedHeight) {
            largeTop = childTop;
            largeBottom = childTop + childHeight;
            smallTop = draggedTop;
            smallBottom = draggedBottom;
        } else {
            smallTop = childTop;
            smallBottom = childTop + childHeight;
            largeTop = draggedTop;
            largeBottom = draggedBottom;
        }
        if (smallBottom > largeTop || smallTop < largeBottom) {
            if (isChildAfter && draggedBottom >= childBottom) {
                $('.ui-sortable-placeholder', that).insertAfter($(this));
            } else if (!isChildAfter && draggedTop <= childTop) {
                $('.ui-sortable-placeholder', that).insertBefore($(this));
                return false;
            }
        }
    });
}

你可以看到重叠检测比以前有点棘手,因为你可能会将一个大项目拖过一个小项目,反之亦然。

这并不完美,但它比默认功能有了很大改进。

答案 2 :(得分:3)

这是@ dioslaska功能的补充。如果你需要在网格中排序(例如你的元素是浮动的),你可以检查子元素的顶部位置,看它是否在同一个“行”中,如下所示:

sort: function (event, ui) {
  var self = $(this),
      width = ui.helper.outerWidth(),
      top = ui.helper.position().top;//changed to ;

  self.children().each(function () {
    if ($(this).hasClass('ui-sortable-helper') || $(this).hasClass('ui-sortable-placeholder')) {
      return true;
    }
    // If overlap is more than half of the dragged item
    var distance = Math.abs(ui.position.left - $(this).position().left),
        before = ui.position.left > $(this).position().left;

    if ((width - distance) > (width / 2) && (distance < width) && $(this).position().top === top) {
      if (before) {
        $('.ui-sortable-placeholder', self).insertBefore($(this));
      } else {
        $('.ui-sortable-placeholder', self).insertAfter($(this));
      }
      return false;
    }
  });
}

答案 3 :(得分:2)

以下是基于毕达哥拉斯定理和比较元素之间距离的网格布局sort方法的实现&#39;中心:

$("#sortable").sortable({
    ...
    sort: sort_jQueryBug8342Fix
});

function sort_jQueryBug8342Fix(e, ui) {

    // ui-sortable-helper: element being dragged
    // ui-sortable-placeholder: invisible item on the original place of dragged item
    var container = $(this);
    var placeholder = container.children('.ui-sortable-placeholder');

    var draggedCenterX = ui.helper.position().left + ui.helper.outerWidth()/2;
    var draggedCenterY = ui.helper.position().top + ui.helper.outerHeight()/2;

    container.children().each(function () {
        var item = $(this);

        if(!item.hasClass( 'ui-sortable-helper' ) && !item.hasClass( 'ui-sortable-placeholder' ) ) {
            var itemCenterX = item.position().left + item.outerWidth()/2;
            var itemCenterY = item.position().top + item.outerHeight()/2;

            // Pythagorean theorem
            var distanceBetweenCenters = Math.sqrt(Math.pow(itemCenterX - draggedCenterX, 2) + Math.pow(itemCenterY - draggedCenterY, 2));

            var minDimension = Math.min(item.outerWidth(), item.outerHeight(), ui.helper.outerWidth(), ui.helper.outerHeight());
            var overlaps = distanceBetweenCenters < (minDimension / 2);

            if (overlaps) {
                if (placeholder.index() > item.index()) {
                    placeholder.insertBefore(item);
                } else {
                    placeholder.insertAfter(item);
                }
                container.sortable('refreshPositions');
                return false;
            }

        }
    });
}

它适用于网格布局和具有接近宽度和高度尺寸的项目,例如4:3或16:10比例的图像缩略图。在这种情况下,它需要50-60%的重叠来触发排序。如果您有非常宽的元素,例如300x50像素(或不同大小的元素),那么我认为它也会起作用,但您必须更多地将它们重叠X轴,例如90%。

注意:如果要对Dropzone.js元素进行排序,则应将&& item.hasClass('dz-preview')添加到第一个if语句中。

答案 4 :(得分:1)

这与您在IE9,FF11和Chrome18中描述的完全相同。

当鼠标至少高于50%时,相交会重叠 我认为这是不正确的文档。

编辑:我在JQuery Bugtracker中找不到与此相关的错误。

答案 5 :(得分:1)

稍微扩展dioslaska的回答。这是一个例子(我称之为)125%重叠http://jsfiddle.net/yj1wwtsd/4/

当你超过25%时,它只会翻转一个元素。在我的情况下,我结合了droppable和sortable,当被拖动的项目在翻转之前可以完全重叠另一个(允许掉落)时感觉更好。

特别需要注意的是最后一行的jQueryUI黑客攻击。如果没有这个,它总是默认为交叉容差,即使sort方法试图做一些不同的事情。这可能会破坏jQueryUI的未来版本(使用1.11.2测试)。

$('#sortable').sortable({
    axis: 'x',
    sort: function (event, ui) {
        var that = $(this);
        var w = ui.helper.outerWidth();
        var centreOfDraggedItem = ui.position.left + w/2;

        that.children().each(function () {
            if ($(this).hasClass('ui-sortable-helper') || $(this).hasClass('ui-sortable-placeholder')) 
                return true;
            var centreOfThisItem =  $(this).position().left + w/2;
            var dist = centreOfDraggedItem - centreOfThisItem;
            var before = centreOfDraggedItem > centreOfThisItem;
            if (Math.abs(dist) < w/2) {
                if (before && dist > w/4) { // moving right
                    $('.ui-sortable-placeholder').insertAfter($(this));
                    return false;
                }
                if (!before && dist < -(w/4)) { // moving left
                    $('.ui-sortable-placeholder').insertBefore($(this));
                    return false;
                }
            }
        });
    },
});
$('#sortable').data('ui-sortable')._intersectsWithPointer = function () {return false;};