簡體   English   中英

滑動時防止觸摸啟動

[英]prevent touchstart when swiping

我在移動設備上有一個可滾動的列表。 他們希望人們能夠通過滑動滾動列表,並且還希望通過點擊來滾動一行 select。

問題是將兩者結合起來。 如果您實際上正在滾動列表,我不希望選擇一行。 這是我發現的:

滾動時不觸發:

  • 點擊
  • mouseup

滾動時觸發:

  • 鼠標按下
  • 觸摸啟動
  • 觸摸端

簡單的解決方案是堅持點擊事件。 但我們發現,在某些 blackberry 設備上,touchstart 與觸發 click 或 mouseup 之間存在非常明顯的延遲。 這種延遲足以使其在這些設備上無法使用。

所以這給我們留下了其他選擇。 但是,使用這些選項,您可以滾動列表而無需觸發您觸摸的行開始滾動。

解決此問題的最佳做法是什么?

var touchmoved;
$('button').on('touchend', function(e){
    if(touchmoved != true){
        // button click action
    }
}).on('touchmove', function(e){
    touchmoved = true;
}).on('touchstart', function(){
    touchmoved = false;
});

您基本上想要做的是檢測什么是滑動,什么是點擊。

我們可以設置一些條件:

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

然后,您還必須為可滾動元素添加偵聽器,但您不必擔心如果手指在touchStarttouchEnd之間移動會發生什么。

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

//西蒙A。

這是我最終想出的,允許通過滑動滾動項目列表,而且每個項目都可以通過點擊“觸發”。 此外,您仍然可以使用鍵盤(使用 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()
}
});

引用 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");
});

其中一些解決方案對我有用,但最后我發現這個輕量級庫更易於設置。

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

它非常靈活,可以檢測觸摸以及滑動、雙擊等。

我有同樣的問題,這是一個適合我的快速解決方案

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

基本上不是立即處理 touchstart,而是等待幾毫秒(本例中為 200 毫秒),然后檢查滾動 position,滾動位置已更改,則我們無需處理 touchstart。

我遇到了這個優雅的解決方案,它使用 jQuery 就像一個魅力。 我的問題是阻止列表項在滾動期間調用它們的觸摸開始事件。 這也應該適用於刷卡。

  1. 將 touchstart 綁定到將使用 class 'listObject' 滾動或滑動的每個項目

    $('.listObject').live('touchstart', touchScroll);
  2. 然后為每個項目分配一個數據對象屬性,定義要調用的 function

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

以下 function 將有效地區分點擊和滾動或滑動。

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

}

我想出了這個,因為我想要一個也可以防止動態鏈接的全局事件。 因此preventDefault()必須在事件監聽器中是可調用的,為此觸摸事件被引用。

檢測與迄今為止在此處發布的大多數解決方案一樣。 在觸摸結束時檢查元素是否仍然相同或者我們是否移動了一些量。

$('li a').on('ontouchstart' in document.documentElement === true ? 'touchClick' : 'click', handleClick);

if('ontouchstart' in document.documentElement === true) {
    var clickedEl = null;
    var touchClickEvent = $.Event('touchClick');
    var validClick = false;
    var pos = null;
    var moveTolerance = 15;
    $(window).on('touchstart', function(e) {
        /* only handle touch with one finger */
        if(e.changedTouches.length === 1) {
            clickedEl = document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY);
            pos = {x: e.touches[0].clientX, y: e.touches[0].clientY};
            validClick = true;
        } else {
            validClick = false;
        }
    }).on("touchmove", function(e) {
        var currentEl = document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY);
        if(
            e.changedTouches.length > 1 ||
            (!$(clickedEl).is(currentEl) && !$.contains(clickedEl, currentEl)) ||
            (Math.abs(pos.y - e.touches[0].clientY) > moveTolerance && Math.abs(pos.x - e.touches[0].clientX) > moveTolerance)
        ) {
            validClick = false;
        }
    }).on("touchend", function(e) {
        if(validClick) {
            /* this allowes calling of preventDefault on the touch chain */
            touchClickEvent.originalEvent = e;
            /* target is used in jQuery event delegation */
            touchClickEvent.target = e.target;
            $(clickedEl).trigger(touchClickEvent);
        }
    });
}

我做了一些不同的工作。 它絕對不是很優雅,當然也不適合大多數情況,但它對我有用。

我一直在使用 jQuery 的 toggleSlide() 來打開和關閉輸入 div,在 touchstart 上觸發幻燈片。 問題是當用戶想要滾動時,觸摸的 div 會打開。 為了阻止這種情況發生(或在用戶注意到之前將其反轉),我在文檔中添加了一個 touchslide 事件,該事件將關閉最后一次觸摸的 div。

更深入地說,這是一個代碼片段:

var lastTouched;

document.addEventListener('touchmove',function(){
    lastTouched.hide();
});

$('#button').addEventListener('touchstart',function(){
    $('#slide').slideToggle();
    lastTouched = $('#slide');
});

全局變量存儲最后觸摸的 div,如果用戶滑動,document.touchmove 事件會隱藏該 div。 有時你會看到一個 div 閃爍,但它可以滿足我的需要,並且足夠簡單,我可以想出。

我使用這段代碼,以便僅在未滑動時觸發按鈕(在觸摸端):

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

jQuery Mobile 有一個.tap()事件,它似乎具有您期望的行為:

jQuery 移動點擊事件在單個目標 object 上發生快速、完整的觸摸事件后觸發。 它相當於標准單擊事件的手勢,在觸摸手勢的釋放 state 上觸發。

這可能不一定回答問題,但可能是一些有用的替代方案。

如果您想對多個元素執行此操作並且還需要鼠標和指針事件:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM