jQuery Drag and Drop на сенсорных устройствах (iPad, Android) - PullRequest
29 голосов
/ 27 апреля 2011

У нас есть веб-сайт, посвященный карточным играм, который широко использует jQuery Draggable & Droppable и работает почти безупречно (при использовании мыши) почти год.

Мы ДЕЙСТВИТЕЛЬНО хотели бы, чтобы сайт работал на устройствах с сенсорным экраном, но, похоже, мы не можем заставить работать функции перетаскивания jQuery и особенно отбрасывать его надежно.

Перетаскивание работает нормально, если перетаскиваемый div не находится внутри другого элемента dom с любым видом смещения, поля, отступов и т. Д. Если это так, перетаскиваемый элемент также смещается от пальца пользователя на аналогичную величину. Может показаться не таким уж большим делом, но это делает интерфейс непригодным для использования.

Падение просто не работает.

Мы исследовали различные варианты, представленные здесь, на SO (постараемся обновить этот пост ссылками на некоторые из них, если смогу), но ни один из них не работает для нас.

Мы также исследовали jQuery Mobile, но он все еще находится в альфа-версии и, тем не менее, кажется, что это скорее платформа для того, чтобы сайт эмулировал интерфейс телефона по сравнению с тем, что мы ищем.

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

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

У кого-нибудь есть идеи? Мы согласились бы с ответом, который поддерживает только iPad, но для этого действительно не требуется рефакторинг существующего сайта.

Спасибо!

Ответы [ 8 ]

36 голосов
/ 12 января 2012

Вставьте это в начало вашего файла .js:

(function ($) {
    // Detect touch support
    $.support.touch = 'ontouchend' in document;
    // Ignore browsers without touch support
    if (!$.support.touch) {
    return;
    }
    var mouseProto = $.ui.mouse.prototype,
        _mouseInit = mouseProto._mouseInit,
        touchHandled;

    function simulateMouseEvent (event, simulatedType) { //use this function to simulate mouse event
    // Ignore multi-touch events
        if (event.originalEvent.touches.length > 1) {
        return;
        }
    event.preventDefault(); //use this to prevent scrolling during ui use

    var touch = event.originalEvent.changedTouches[0],
        simulatedEvent = document.createEvent('MouseEvents');
    // Initialize the simulated mouse event using the touch event's coordinates
    simulatedEvent.initMouseEvent(
        simulatedType,    // type
        true,             // bubbles                    
        true,             // cancelable                 
        window,           // view                       
        1,                // detail                     
        touch.screenX,    // screenX                    
        touch.screenY,    // screenY                    
        touch.clientX,    // clientX                    
        touch.clientY,    // clientY                    
        false,            // ctrlKey                    
        false,            // altKey                     
        false,            // shiftKey                   
        false,            // metaKey                    
        0,                // button                     
        null              // relatedTarget              
        );

    // Dispatch the simulated event to the target element
    event.target.dispatchEvent(simulatedEvent);
    }
    mouseProto._touchStart = function (event) {
    var self = this;
    // Ignore the event if another widget is already being handled
    if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
        return;
        }
    // Set the flag to prevent other widgets from inheriting the touch event
    touchHandled = true;
    // Track movement to determine if interaction was a click
    self._touchMoved = false;
    // Simulate the mouseover event
    simulateMouseEvent(event, 'mouseover');
    // Simulate the mousemove event
    simulateMouseEvent(event, 'mousemove');
    // Simulate the mousedown event
    simulateMouseEvent(event, 'mousedown');
    };

    mouseProto._touchMove = function (event) {
    // Ignore event if not handled
    if (!touchHandled) {
        return;
        }
    // Interaction was not a click
    this._touchMoved = true;
    // Simulate the mousemove event
    simulateMouseEvent(event, 'mousemove');
    };
    mouseProto._touchEnd = function (event) {
    // Ignore event if not handled
    if (!touchHandled) {
        return;
    }
    // Simulate the mouseup event
    simulateMouseEvent(event, 'mouseup');
    // Simulate the mouseout event
    simulateMouseEvent(event, 'mouseout');
    // If the touch interaction did not move, it should trigger a click
    if (!this._touchMoved) {
      // Simulate the click event
      simulateMouseEvent(event, 'click');
    }
    // Unset the flag to allow other widgets to inherit the touch event
    touchHandled = false;
    };
    mouseProto._mouseInit = function () {
    var self = this;
    // Delegate the touch handlers to the widget's element
    self.element
        .on('touchstart', $.proxy(self, '_touchStart'))
        .on('touchmove', $.proxy(self, '_touchMove'))
        .on('touchend', $.proxy(self, '_touchEnd'));

    // Call the original $.ui.mouse init method
    _mouseInit.call(self);
    };
})(jQuery);

Позвони мне утром;) (это действительно высокомерно, я не писал это решение, хотя хотел бы, чтобы у меня было это, я бы сослался на него, если бы вспомнил, где я его нашел, если кто-нибудь знает, откуда взялся этот код пожалуйста, прокомментируйте и отметьте это лицо)

ОБНОВЛЕНИЕ: Вот, пожалуйста: Вот где я нашел это

16 голосов
/ 13 мая 2012

Я предлагаю JQuery UI Touch Punch .Я протестировал его на iOS 5 и Android 2.3, и он отлично работает на обоих.

4 голосов
/ 24 сентября 2012

Старый поток, который я знаю .......

Проблема с ответом @likwid_t заключается в том, что он блокирует также любой вход или другой элемент, который должен реагировать на «щелчки» (например, входы)так что я написал это решение.Это решение позволило использовать любую существующую библиотеку перетаскивания, основанную на событиях mousedown, mousemove и mouseup, на любом сенсорном устройстве (или cumputer).Это также кросс-браузерное решение.

Я тестировал на нескольких устройствах, и оно работает быстро (в сочетании с функцией перетаскивания в ThreeDubMedia (см. Также http://threedubmedia.com/code/event/drag)). Это jQuery).решение, так что вы можете использовать его только с библиотеками jQuery. Я использовал jQuery 1.5.1 для него, потому что некоторые более новые функции не работают должным образом с IE9 и выше (не тестируется с более новымиверсии jQuery).

До вы добавляете любую операцию перетаскивания к событию , сначала необходимо вызвать эту функцию :

simulateTouchEvents(<object>);

Вы также можете заблокировать все компоненты / дочерние элементы для ввода или для ускорения обработки событий, используя следующий синтаксис:

simulateTouchEvents(<object>, true); // ignore events on childs

Вот код, который я написал. Я использовал несколько хороших трюковдля ускорения оценки (см. код).

function simulateTouchEvents(oo,bIgnoreChilds)
{
 if( !$(oo)[0] )
  { return false; }

 if( !window.__touchTypes )
 {
   window.__touchTypes  = {touchstart:'mousedown',touchmove:'mousemove',touchend:'mouseup'};
   window.__touchInputs = {INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,'input':1,'textarea':1,'select':1,'option':1};
 }

$(oo).bind('touchstart touchmove touchend', function(ev)
{
    var bSame = (ev.target == this);
    if( bIgnoreChilds && !bSame )
     { return; }

    var b = (!bSame && ev.target.__ajqmeclk), // Get if object is already tested or input type
        e = ev.originalEvent;
    if( b === true || !e.touches || e.touches.length > 1 || !window.__touchTypes[e.type]  )
     { return; } //allow multi-touch gestures to work

    var oEv = ( !bSame && typeof b != 'boolean')?$(ev.target).data('events'):false,
        b = (!bSame)?(ev.target.__ajqmeclk = oEv?(oEv['click'] || oEv['mousedown'] || oEv['mouseup'] || oEv['mousemove']):false ):false;

    if( b || window.__touchInputs[ev.target.tagName] )
     { return; } //allow default clicks to work (and on inputs)

    // https://developer.mozilla.org/en/DOM/event.initMouseEvent for API
    var touch = e.changedTouches[0], newEvent = document.createEvent("MouseEvent");
    newEvent.initMouseEvent(window.__touchTypes[e.type], true, true, window, 1,
            touch.screenX, touch.screenY,
            touch.clientX, touch.clientY, false,
            false, false, false, 0, null);

    touch.target.dispatchEvent(newEvent);
    e.preventDefault();
    ev.stopImmediatePropagation();
    ev.stopPropagation();
    ev.preventDefault();
});
 return true;
}; 

Что он делает: Сначала он преобразует события одного касания в события мыши. Он проверяет, вызвано ли событие элементом на / в элементе.это нужно тащить вокруг. Еслиэто элемент ввода, такой как input, textarea и т. д., он пропускает перевод или, если к нему присоединено стандартное событие мыши, он также пропускает перевод.

Результат: каждый элемент перетаскиваемого элемента все еще работает.

Счастливого кодирования, привет, Эрвин Хаантес

3 голосов
/ 30 ноября 2012

Я создал плагин jQuery на основе ответа Эрвина: https://github.com/RushPL/jquery.touch-mouse

0 голосов
/ 19 января 2017

Проверено на HTC One M8 под Android 6.13 / Samsung Galaxy Tab S2

function simulateMouseEvent (event, simulatedType) { //use this function to simulate mouse event

// restriction to preserve input use
    window.__touchInputs = {INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,'input':1,'textarea':1,'select':1,'option':1};
    if( window.__touchInputs[event.target.tagName] ) return ;

} 
0 голосов
/ 12 сентября 2016

Данный сработал для меня:

eventAfterRender: function (event, element, view ) {
         element.draggable();
},
0 голосов
/ 09 июля 2015

У LikWidT самое простое решение - это ссылка на сайт, на который ссылаются.Было бы здорово, если бы кто-нибудь из программистов пользовательского интерфейса JQuery мог добавить этот код или подобный к своему пакету.Jquery, безусловно, является самым простым пакетом для создания контента перетаскивания для веб-разработчиков ... это, к сожалению, серьезный недостаток, поскольку почти все устройства в настоящее время имеют сенсорные экраны.Сейчас я пишу код для Surface Pro, который лично открывает мне глаза на эти проблемы.

Просто снова ссылаюсь на сайт: https://github.com/furf/jquery-ui-touch-punch

Редактировать: Также, чтобы уточнить, насколько просто это исправление,Сначала я должен был убедиться в том, что я переупорядочил мои включаемые файлы так, чтобы файл JQuery Javascript был сначала, затем Jquery UI Javascript, а затем мои CSS-файлы.Затем я просто копирую / вставляю ниже включаемых файлов код Javascript в пост выше и все.Я не модифицировал код, это просто функция, которая ищет любые прикосновения в реальном времени и преобразует их в эквивалентные действия мыши.Отсюда и мои вышеприведенные утверждения для кодеров JQuery.

0 голосов
/ 22 июля 2011

Вы можете попробовать этот плагин, но, кажется, работает для iphone, ipod и ipad. Не уверен, решит ли ты проблему. Может быть конкретным ...

http://code.google.com/p/jquery-ui-for-ipad-and-iphone/

Но android все еще ищет решение.

Дайте мне знать, если это поможет. С уважением, Рикардо Родригес

...