предотвратить сенсорный запуск при смахивании - PullRequest
38 голосов
/ 15 августа 2011

У меня есть прокручиваемый список на мобильном устройстве. Они хотят, чтобы люди могли прокручивать список с помощью пролистывания, а также выбирать строку, нажав.

Улов сочетает в себе два. Я не хочу, чтобы строка была выбрана, если вы на самом деле прокручиваете список. Вот что я нашел:

Не срабатывает при прокрутке:

  • нажмите
  • mouseup

Срабатывает при прокрутке:

  • Музаун
  • Touchstart
  • штучка

Простое решение - просто придерживаться события щелчка. Но мы обнаруживаем, что на некоторых устройствах Blackberry ОЧЕНЬ заметно задерживается между сенсорным запуском и последующим срабатыванием либо щелчка, либо мыши. Эта задержка достаточно значительна, чтобы сделать ее непригодной для использования на этих устройствах.

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

Какая лучшая практика здесь для решения этой проблемы?

Ответы [ 11 ]

45 голосов
/ 20 августа 2015
var touchmoved;
$('button').on('touchend', function(e){
    if(touchmoved != true){
        // button click action
    }
}).on('touchmove', function(e){
    touchmoved = true;
}).on('touchstart', function(){
    touchmoved = false;
});
23 голосов
/ 20 февраля 2012

Что вы в основном хотите сделать, это определить, что такое свайп и что такое щелчок.

Мы можем установить некоторые условия:

  1. Проведите, когда вы касаетесь в точкеp1, затем переместите палец в точку p2, продолжая удерживать палец на экране, затем отпустите.
  2. Щелчок - это нажатие, когда вы начинаете касание и заканчиваете касание того же элемента.

Итак, если вы храните координаты того, где произошла ваша touchStart, вы можете измерить разницу в touchEnd.Если изменение достаточно велико, считайте его проведением, в противном случае считайте его щелчком.

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

// grab an element which you can click just as an example
var clickable = document.getElementById("clickableItem"),
// set up some variables that we need for later
currentElement,
clickedElement;

// set up touchStart event handler
var onTouchStart = function(e) {
    // store which element we're currently clicking on
    clickedElement = this;
    // listen to when the user moves finger
    this.addEventListener("touchMove" onTouchMove);
    // add listener to when touch end occurs
    this.addEventListener("touchEnd", onTouchEnd);
};
// when the user swipes, update element positions to swipe
var onTouchMove = function(e) {
    // ... do your scrolling here

    // store current element
    currentElement = document.elementFromPoint(x, y);
    // if the current element is no longer the same as we clicked from the beginning, remove highlight
    if(clickedElement !== currentElement) {
        removeHighlight(clickedElement);
    }
};
// this is what is executed when the user stops the movement
var onTouchEnd = function(e) {
    if(clickedElement === currentElement) {
        removeHighlight(clickedElement);
        // .... execute click action
    }

    // clean up event listeners
    this.removeEventListener("touchMove" onTouchMove);
    this.removeEventListener("touchEnd", onTouchEnd);
};
function addHighlight(element) {
    element.className = "highlighted";
}
function removeHighlight(element) {
    element.className = "";
}
clickable.addEventListener("touchStart", onTouchStart);

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

var scrollable = document.getElementById("scrollableItem");

// set up touchStart event handler
var onTouchStartScrollable = function(e) {
    // listen to when the user moves finger
    this.addEventListener("touchMove" onTouchMoveScrollable);
    // add listener to when touch end occurs
    this.addEventListener("touchEnd", onTouchEndScrollable);
};
// when the user swipes, update element positions to swipe
var onTouchMoveScrollable = function(e) {
    // ... do your scrolling here
};
// this is what is executed when the user stops the movement
var onTouchEndScrollable = function(e) {
    // clean up event listeners
    this.removeEventListener("touchMove" onTouchMoveScrollable);
    this.removeEventListener("touchEnd", onTouchEndScrollable);
};
scrollable.addEventListener("touchStart", onTouchStartScrollable);

// Саймон А.

17 голосов
/ 21 февраля 2012

Вот то, что я в конце концов придумал, чтобы можно было прокручивать список элементов с помощью пролистывания, а также «запускать» каждый элемент с помощью касания. Кроме того, вы все еще можете использовать с клавиатурой (используя onclick).

Я думаю, что это похоже на ответ Netlight_Digital_Media. Мне нужно изучить это немного больше.

$(document)
// log the position of the touchstart interaction
.bind('touchstart', function(e){ 
  touchStartPos = $(window).scrollTop();
})
// log the position of the touchend interaction
.bind('touchend', function(e){
  // calculate how far the page has moved between
  // touchstart and end. 
  var distance = touchStartPos - $(window).scrollTop();

  var $clickableItem; // the item I want to be clickable if it's NOT a swipe

  // adding this class for devices that
  // will trigger a click event after
  // the touchend event finishes. This 
  // tells the click event that we've 
  // already done things so don't repeat

  $clickableItem.addClass("touched");      

  if (distance > 20 || distance < -20){
        // the distance was more than 20px
        // so we're assuming they intended
        // to swipe to scroll the list and
        // not selecting a row. 
    } else {
        // we'll assume it was a tap 
        whateverFunctionYouWantToTriggerOnTapOrClick()
    }
});


$($clickableItem).live('click',function(e){
 // for any non-touch device, we need 
 // to still apply a click event
 // but we'll first check to see
 // if there was a previous touch
 // event by checking for the class
 // that was left by the touch event.
if ($(this).hasClass("touched")){
  // this item's event was already triggered via touch
  // so we won't call the function and reset this for
  // the next touch by removing the class
  $(this).removeClass("touched");
} else {
  // there wasn't a touch event. We're
  // instead using a mouse or keyboard
  whateverFunctionYouWantToTriggerOnTapOrClick()
}
});
6 голосов
/ 29 мая 2013

Цитирование из DA.:

Это рабочий пример:

var touch_pos;
$(document).on('touchstart', '.action-feature', function(e) {
  e.preventDefault();
  touch_pos = $(window).scrollTop();
}).on('click touchend', '.action-feature', function(e) {
  e.preventDefault();
  if(e.type=='touchend' && (Math.abs(touch_pos-$(window).scrollTop())>3)) return;
  alert("only accessed when it's a click or not a swipe");
});
3 голосов
/ 27 мая 2014

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

Tocca.js: https://github.com/GianlucaGuarini/Tocca.js

Это довольно гибкий и обнаруживаеткоснитесь, а также проведите, дважды нажмите и т. д.

2 голосов
/ 27 марта 2014

У меня была такая же проблема, вот быстрое решение, которое работает для меня

$(document).on('touchstart', 'button', function(evt){ 
    var oldScrollTop = $(window).scrollTop();
    window.setTimeout( function() {
        var newScrollTop = $(window).scrollTop();
        if (Math.abs(oldScrollTop-newScrollTop)<3) $button.addClass('touchactive');
    }, 200);
});

По сути, вместо немедленной обработки сенсорного запуска, подождите несколько миллисекунд (в этом примере 200 мс), затем проверьте положение прокрутки, изменили ли положение прокрутки, тогда нам не нужно обрабатывать сенсорный запуск.

1 голос
/ 30 мая 2013

Я столкнулся с этим элегантным решением, которое работает как шарм, используя jQuery.Моя проблема состояла в том, чтобы не дать элементам списка вызывать событие сенсорного запуска во время прокрутки.Это также должно работать для считывания.

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

    $('.listObject').live('touchstart', touchScroll);
    
  2. Затем каждому элементу присваивается объект данных, определяющий вызываемую функцию

    <button class='listObject' data-object=alert('You are alerted !')>Alert Me</button>
    

Следующая функция будет эффективно различать касание и прокрутку или пролистывание.

function touchScroll(e){

    var objTarget = $(event.target);

    if(objTarget.attr('data-object')){
        var fn = objTarget.attr('data-object'); //function to call if tapped    
    }   

    if(!touchEnabled){// default if not touch device
        eval(fn);
        console.log("clicked", 1);
        return;
    }

    $(e.target).on('touchend', function(e){
        eval(fn); //trigger the function
        console.log("touchEnd")      
        $(e.target).off('touchend');
    });

    $(e.target).on('touchmove', function(e){
        $(e.target).off('touchend');
        console.log("moved")
    }); 

}
0 голосов
/ 12 декабря 2017

, если вы хотите сделать это для нескольких элементов, а также для событий мыши и указателя:

var elems = $('YOURMULTISELECTOR'); // selector for multiple elements
elems.unbind('mousdown pointerdown touchstart touchmove mouseup pointerup touchend');
var elem = null;
elems.on('mousdown pointerdown touchstart', function (e) {
    elem = yourSingleSelector(e);
}).on('touchmove', function (e) {
    elem = null;                
}).on('mouseup pointerup touchend', function (e) { 
    if (elem == yourSingleSelector(e)) {                    
        // do something
    }
});
0 голосов
/ 28 января 2015

jQuery Mobile имеет событие .tap(), которое, по-видимому, имеет ожидаемое поведение:

Событие касания jQuery Mobile срабатывает после быстрого, полного события касаниячто происходит на одном целевом объекте.Это жест, эквивалентный стандартному событию щелчка, которое запускается в состоянии отпускания сенсорного жеста.

Это может не обязательно отвечать на вопрос, но может быть полезной альтернативой некоторым.

0 голосов
/ 22 ноября 2014

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

var startY;
var yDistance;

function touchHandler(event) {
    touch = event.changedTouches[0];
    event.preventDefault();
}

$('.button').on("touchstart", touchHandler, true);
$('.button').on("touchmove", touchHandler, true);

$('.button').on("touchstart", function(){
    startY = touch.clientY;
});

$('.button').on('touchend', function(){

    yDistance = startY - touch.clientY;

    if(Math.abs(yDist) < 30){

        //button response here, only if user is not swiping
        console.log("button pressed")
    }
});
...