проверка, если touchend приходит после перетаскивания

У меня есть код, который меняет класс таблицы. На телефоне иногда таблица будет слишком широкой для экрана, и пользователь будет перетаскивать/прокручивать ее, чтобы увидеть ее содержимое. Однако, когда они касаются и перетаскивают стол, он срабатывает при каждом перетаскивании.

Как проверить, произошло ли касание в результате перетаскивания касанием? Я пробовал отслеживать dragstart и dragend, но не смог заставить это работать, и это кажется неэлегантным подходом. Есть ли что-то, что я мог бы добавить ниже, что, по сути, определило бы: «Это касание произошло в конце перетаскивания?»

$("#resultTable").on("touchend","#resultTable td",function(){ 
        $(this).toggleClass('stay');
});

Заранее благодарю за вашу помощь.

PS - используется последняя версия jquery, и хотя обычный клик работает, он очень медленный по сравнению с touchend.


person Konrad Lawson    schedule 02.10.2012    source источник


Ответы (4)


Используйте два слушателя:

Сначала установите переменную в false:

var dragging = false;

Затем ontouchmove установите перетаскивание в значение true

$("body").on("touchmove", function(){
      dragging = true;
});

Затем по завершении перетаскивания проверьте, выполняется ли перетаскивание, и если да, то считайте его перетаскиванием:

$("body").on("touchend", function(){
      if (dragging)
          return;

      // wasn't a drag, just a tap
      // more code here
});

Сенсорный конец по-прежнему будет срабатывать, но завершится до того, как будет запущен ваш сценарий касания.

Чтобы в следующий раз, когда вы коснетесь, он еще не был установлен как перетаскиваемый, сбросьте его обратно на false при касании.

$("body").on("touchstart", function(){
    dragging = false;
});
person lededje    schedule 17.10.2012
comment
в if из touchend я считаю, что вы также должны установить перетаскивание обратно в false. Кроме этого, это работает хорошо. - person alex-i; 05.02.2013
comment
Незачем; в следующий раз, когда вы прикоснетесь, он снова установит значение false. - person lededje; 05.02.2013
comment
@lededje Зачем ему возвращать значение false, если у вас нет кода для его сброса? - person Michael Martin-Smucker; 20.11.2013
comment
@Крис, к сожалению? - person lededje; 08.07.2014
comment
Я был просто расстроен тем, что это нелогичное решение — лучший способ решить проблему. ваш ответ, безусловно, помог, и я проголосовал за него. - person northamerican; 09.07.2014
comment
@chris Я согласен, что этот ответ - грязь, но, увы, в спецификацию не было добавлено ничего лучшего :( - person lededje; 11.07.2014
comment
Здесь есть множество хакерских исправлений для этой проблемы, но это лучший ответ. сафари это шутка - person Sean T; 22.08.2019

Похоже, одно из решений моей проблемы находится здесь:

http://alxgbsn.co.uk/2011/08/16/event-delegation-for-touch-events-in-javascript/

Этот фрагмент кода обнаруживает любое движение после touchstart, чтобы прервать поведение касания после tapend.

var tapArea, moved, startX, startY;

tapArea = document.querySelector('#list'); //element to delegate
moved = false; //flags if the finger has moved
startX = 0; //starting x coordinate
startY = 0; //starting y coordinate

//touchstart           
tapArea.ontouchstart = function(e) {

    moved = false;
    startX = e.touches[0].clientX;
    startY = e.touches[0].clientY;
};

//touchmove    
tapArea.ontouchmove = function(e) {

    //if finger moves more than 10px flag to cancel
    //code.google.com/mobile/articles/fast_buttons.html
    if (Math.abs(e.touches[0].clientX - startX) > 10 ||
        Math.abs(e.touches[0].clientY - startY) > 10) {
            moved = true;
    }
};

//touchend
tapArea.ontouchend = function(e) {

    e.preventDefault();

    //get element from touch point
    var element = e.changedTouches[0].target;

    //if the element is a text node, get its parent.
    if (element.nodeType === 3) { 
        element = element.parentNode;
    }

    if (!moved) {
        //check for the element type you want to capture
        if (element.tagName.toLowerCase() === 'label') {
            alert('tap');
        }
    }
};

//don't forget about touchcancel!
tapArea.ontouchcancel = function(e) {

    //reset variables
    moved = false;
    startX = 0;
    startY = 0;
};

Подробнее здесь: https://developers.google.com/mobile/articles/fast_buttons.

person Konrad Lawson    schedule 02.10.2012

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

person KoU_warch    schedule 02.10.2012
comment
EH_warch, спасибо за ответ. Хм, приношу извинения, я имею в виду не перетаскивание элементов, а прокрутку по экрану - другой вид перетаскивания, если хотите. Представьте себе таблицу с 6 столбцами на узком экране iPhone. Чтобы увидеть последние три столбца, нужно коснуться и провести пальцем влево, чтобы увидеть остальную часть таблицы. Однако обычно вы не хотите, чтобы это прикосновение распознавалось базовыми элементами как касание, что в моем коде выше происходит в настоящее время. Как я могу распознавать только касание, а не касание + перетаскивание без использования метода медленного щелчка () (касание происходит намного быстрее) - person Konrad Lawson; 02.10.2012
comment
О, хорошо, я думаю, вы ищете это, тогда trott.github.com/LightningTouch/# /молния-основной - person KoU_warch; 02.10.2012
comment
Спасибо что подметил это! Похоже, что Lightning Touch включает в себя некоторый код, который объясняет проблему, но это 250 дополнительных строк кода, что является излишним. Я собираюсь посмотреть, смогу ли я извлечь что-то полезное из этого, используя touchmove. - person Konrad Lawson; 02.10.2012

Чтобы сократить решение @lededge, это может помочь.

$("body").on("touchmove", function(){
   dragging = true;
}).on("touchend", function(){
   if (dragging)
      return;
}).on("touchstart", function(){
   dragging = false;
});
person Jessiemar Pedrosa    schedule 05.04.2019