Подтвердить что ты не робот

Параметр jQuery UI sortable допуска не работает должным образом

Вот часть из документации jQuery UI для параметра tolerance:

Так происходит переупорядочение во время перетаскивания. Возможные значения: 'intersect', 'pointer'. В некоторых настройках "указатель" более естественен.

intersect: draggable перекрывает отбрасываемый не менее 50%

По умолчанию используется intersect, но если указатель мыши не находится над сортируемыми элементами, сортировка не выполняется, независимо от того, что элемент перетаскивания не менее 50% по сравнению с другим сортируемым элементом (функциональность, которую я ожидаю). происходит и на демонстрационной странице (см. выше)

Является ли это ошибкой в ​​пользовательском интерфейсе jQuery, или я понимаю, что это неправильно?

4b9b3361

Ответ 1

Это происходит точно так же, как описано в IE9, FF11 и Chrome18.

Пересечение пересекается, когда мышь по крайней мере на 50% выше.
Я думаю, что это документация, которая неверна.

EDIT: я не обнаружил ошибок, связанных с этим в JQuery Bugtracker.

Ответ 2

Для тех, у кого такая же проблема, обходной путь, который я использую:

$('#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;
            }
        });
    },
});​

Это работает для горизонтальной сортировки, для вертикального изменения outerWidth до outerHeight и position.left до position.top.

Вот полный рабочий пример

Ответ 3

У меня есть неравномерно отсортированные элементы, и это ухудшает ситуацию. Я изменил код диосаски, чтобы изменить порядок, когда дно обработчика проходит нижнюю часть дочернего элемента (при движении вниз) и то же самое для вершин...

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;
            }
        }
    });
}

Вы можете видеть, что обнаружение перекрытия немного сложнее, чем раньше, поскольку вы можете перетаскивать большой элемент по маленькому элементу или наоборот.

Это не идеально, но это огромное улучшение по сравнению с функциональностью по умолчанию.

Ответ 4

Здесь добавляется функция @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;
    }
  });
}

Ответ 5

Расширение на диосласке слегка ответит. Вот пример, который нужно сделать (что я буду называть) 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;};

Ответ 6

Вот моя реализация метода sort для раскладки сетки на основе теоремы Пифагора и расстояния между центрами сравниваемых элементов:

$("#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.