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

Что происходит с jQuery UI Sortable на устройстве с сенсорным экраном?

Я использую jQuery UI Sortable.

Я разрабатываю только мобильный сайт, поэтому я посмотрел, как сопоставить события касания к событиям мыши, чтобы это работало, и в итоге использовал код Олега Слободского.

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

Example

Когда я пытаюсь второй раз перетащить один из этих розовых коробок, вместо того чтобы появиться под моим пальцем и переместиться вместе с ним, он начинается с ширины коробки, слева или справа, а затем прыгает под пальцем.

Я установил пример jsFiddle. Нажмите кнопку attach, чтобы добавить jQuery Sortable в элементы списка.

Я пробовал много вещей, в том числе играя с событием change и пытаюсь перестроить его обратно, но я не мог заставить его надежно работать.

Как я могу остановить эту проблему?

4b9b3361

Ответ 1

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

Чтобы прояснить симптом, это то, что первоначально перетаскиваемый элемент всегда тот, который перетаскивается при последующих перетаскиваниях. Если вы начнете перетаскивать b, при последующих перетаскиваниях b будет та, которая всегда перемещается. Аналогично для a и c.

Это заставило меня спросить, возможно ли, что событие "переработано". Я подтвердил, что значения pageX и pageY были правильными в событии touchstarttouchmove), но значения, попадающие в _mouseDown в Sortable, были неправильными. Итак, я пошел в jquery.ui.mouse.js и посмотрел там _mouseDown. Я подтвердил, что соответствующие значения прошли, но что обработчик вышел из этой строки в верхней части метода:

// don't let more than one widget handle mouseStart
if( mouseHandled ) { return };

Итак, я начал смотреть на mouseHandled. Была только одна строка, где это было reset назад к false - следующий слушатель вверху:

$( document ).mouseup( function( e ) {
    mouseHandled = false;
});

Я понял, что должен быть рядом. Я просмотрел метод _touchEnd в надстройке совместимости, который вы используете:

_touchEnd: function(event) {
   this.element.unbind("touchmove." + this.widgetName).unbind("touchend." + this.widgetName);
   this._mouseUp(event);
}, 

Обратите внимание, что _mouseUp вызывается только сам виджет, а не document! Таким образом, ясно, что mouseHandled никогда не был reset. Итак, я добавил строку document для отправки _touchEnd:

_touchEnd: function(event) {
   this.element.unbind("touchmove." + this.widgetName).unbind("touchend." + this.widgetName);
   this._mouseUp(event);
   $(document).trigger('mouseup', event);
}, 

И престо, все работало правильно.

Итак, в общем, эта одна строка является магической:

$(document).trigger('mouseup', event);

Рабочая вилка здесь [прямая ссылка для просмотра iOS].


Примечание. Я также изменил эту строку:

/ iPad | iPhone /.test(navigator.userAgent) && (function($) {

To:

/iPad|iPhone|iPod/.test(navigator.userAgent) && (function($) {

Потому что он не работал должным образом с пробелами, и вы должны включить поддержку iPod touch.