2014-08-29 83 views
30

我正在使用一些javascript UI,並使用大量觸摸事件(如'touchend')來改進觸摸設備的響應。不過,也有被竊聽我JavaScript touchend與點擊困境

我已經看到,許多開發人員打成一片「touchend」,並在同一事件「點擊」一些邏輯問題...。在許多情況下,它不會傷害,但實質上該函數將在觸摸設備上兩次閃光:

button.on('click touchend', function(event) { 
    // this fires twice on touch devices 
}); 

有人建議,人們可以檢測觸摸能力,並適當例如設置事件:

var myEvent = ('ontouchstart' in document.documentElement) ? 'touchend' : 'click'; 
button.on(myEvent, function(event) { 
    // this fires only once regardless of device 
}); 

上面的問題是,它會在支持觸摸和鼠標的設備上中斷。如果用戶當前在雙輸入設備上使用鼠標,「點擊」將不會觸發,因爲只有「touchend」被分配給該按鈕。

另一種解決方案是檢測設備(例如「iOS」)並根據以下事件分配事件: Click event called twice on touchend in iPad。 當然,上述鏈接中的解決方案僅適用於iOS(不適用於Android或其他設備),並且似乎更像是一種「黑客」來解決相當基本的問題。

另一解決方案是,以檢測鼠標移動,和具有觸摸能力結合起來,以找出如果用戶在鼠標或觸摸。問題當然是,用戶可能不會將鼠標從想要檢測的時候移開...

我能想到的最可靠的解決方案是使用簡單的debounce函數來簡單地確保函數在短時間間隔內觸發一次(例如100ms):

button.on('click touchend', $.debounce(100, function(event) { 
    // this fires only once on all devices 
})); 

我錯過了什麼,或者沒有人有更好的建議嗎?

編輯:我發現我的帖子,這表明了類似的解決方案,上述後此鏈接: How to bind 'touchstart' and 'click' events but not respond to both?

+2

沒有任何解決方案... Modernizr只是檢測'觸摸'。該事件在觸摸設備上仍會觸發兩次。或者,如果您爲觸摸設備(通過modernizr)分配「觸摸」事件,它將停止對在多個Windows8設備等雙輸入設備上使用鼠標的用戶的工作。 – suncat100 2014-08-29 16:34:13

回答

24

研究了一天之後,我想最好的解決方法就是堅持點擊並使用https://github.com/ftlabs/fastclick刪除觸摸延遲。我不是100%確定這是有效的touchend,但至少不遠。

我沒有想出一個辦法來禁止使用stopPropagationpreventDefault觸摸觸發事件兩次,但這是不可靠的,因爲它可以與根據元件等觸摸手勢它應用於干擾:

button.on('touchend click', function(event) { 
    event.stopPropagation(); 
    event.preventDefault(); 
    // this fires once on all devices 
}); 

我實際上尋找一個解決方案,以touchstart一些UI元素結合起來,但我看不出如何能與點擊除上述解決方案相互組合。

+0

有沒有一種原生的方式來檢測瀏覽器是否支持touchstart/end? – BenRacicot 2015-11-09 21:13:08

3

已回答此問題,但可能需要更新。

根據a notice from Google,如果將下面的行包含在<head>元素中,則不會再有300-350ms的延遲。

<meta name="viewport" content="width=device-width"> 

就是這樣!點擊和觸摸事件之間不會有任何區別!

+0

這很有趣。也許有時間擺脫fastclick.js ...我會在移動瀏覽器中測試一下。 – suncat100 2017-02-11 03:50:51

+0

Meta標籤應放置在'head'標籤中,而不是'header'標籤。 – James 2017-03-16 14:38:57

+1

這對我來說並非如此。 – skybondsor 2017-07-30 22:02:25

0

你好,你可以實現下面的方法。

function eventHandler(event, selector) { 
    event.stopPropagation(); // Stop event bubbling. 
    event.preventDefault(); // Prevent default behaviour 
    if (event.type === 'touchend') selector.off('click'); // If event type was touch turn off clicks to prevent phantom clicks. 
} 

// Implement 
$('.class').on('touchend click', function(event) { 
    eventHandler(event, $(this)); // Handle the event. 
    // Do somethings... 
}); 
0

debounce功能將延遲每次點擊的處理爲100毫秒:

button.on('click touchend', $.debounce(100, function(event) { 
    // this is delayed a minimum of 100 ms 
})); 

相反,我創建了一個cancelDuplicates功能觸發向右走,但在10 ms內的任何後續調用將被取消:

function cancelDuplicates(fn, threshhold, scope) { 
    if (typeof threshhold !== 'number') threshhold = 10; 
    var last = 0; 

    return function() { 
     var now = +new Date; 

     if (now >= last + threshhold) { 
      last = now; 
      fn.apply(scope || this, arguments); 
     } 
    }; 
} 

用法:

button.on('click touchend', cancelDuplicates(function(event) { 
    // This fires right away, and calls within 10 ms after are cancelled. 
}));