2010-05-23 100 views
34

在使用交互式DOM元素執行單個頁面JavaScript應用程序時我發現「mouseover-mousemove-mousedown-mouseup-click」順序發生在之後touchstart-touchmove-touchend」事件序列。使用Javascript防止移動Safari/iPhone中的觸摸事件產生鼠標仿真事件(即,單擊)

我還發現,有可能防止由touchstart活動期間做一個「event.preventDefault()」發生的「mouse*-click」事件,但只有然後,而不是在touchmovetouchend。這是一個奇怪的設計,因爲在touchstart期間不可能知道用戶是否意圖拖動或輕掃,或者只是點擊/點擊該項目。

我最終設置了一個與時間戳綁定的「ignore_next_click」標誌,但這顯然不是很乾淨。

有沒有人知道這樣做的更好方法,還是我們錯過了什麼?

注意的是,雖然「點擊」可以被認定爲「touchstart-touchend」序列(即沒有「touchmove」),有一些事情,比如鍵盤輸入焦點,可適當click事件時纔會發生。

+0

我很感興趣,iPad的Safari瀏覽器的觸摸事件過於一部分,但它不是我清楚你想解決哪些具體問題。如果你仍然在處理這個問題,或者解決了這個問題,那麼請細心闡述一下? – Tim 2010-08-01 13:04:10

+0

我希望能夠處理某些事件,如拖放,並且還能夠處理「點擊」事件。我必須將「單擊」事件作爲適當的「單擊」事件(而不是touchstart/touchend)來處理,因爲某些事情(例如鍵盤輸入焦點)可能只能在單擊事件處理程序中激活。 – 2010-10-01 06:47:14

+0

這個問題非常討厭,也影響到Android。 – 2011-04-26 18:06:30

回答

4

我遇到了類似的問題,使跨平臺的HTML5/JS應用程序。對我來說唯一真正的答案是preventDefault關於觸摸事件,並根據我的邏輯實際管理觸摸狀態和點擊,拖動等事件。這聽起來比實際上更令人生畏,但模仿的點擊/鼠標事件在大多數移動瀏覽器上都能很好地工作。

點擊和額外鼠標序列都在那裏爲您提供方便(和兼容性)。我的經驗法則 - 如果它是爲了您的方便,但它不方便,最好殺死它。

只要輸入框,他們只需要touchend事件。我殺了點擊/鼠標事件,並且仍然能夠讓移動瀏覽器正確地響應輸入。如果它仍然給你的問題,你可以修改事件處理只在非輸入剿事件:

function touchHandler(event) { 
    var shouldIgnore = event.target != null 
      && (event.target.tagName.toLowerCase() == "input" || event.target.tagName.toLowerCase() == "textarea"); 

    if(!shouldIgnore) e.preventDefault(); 
} 
+0

我在iOS5和Android 2.2.1上都測試了這個解決方案,問題是如果我在'touchstart'上防止默認,'click'不會觸發,但我無法滾動頁面。如果我在'touchend'上防止默認,它就會在iOS上工作(只在輕敲時),但在Android上觸發'click'。你有沒有注意到同樣的問題?在這裏測試:http://jsfiddle.net/3TBVc/ – 2012-04-10 13:49:59

+0

是的,我遇到了這個問題(表現在幾個方面)。這似乎是Android iOS跨平臺iOS <->更大的痛苦之一。這需要一些調整,但通過取消正確的事情,你通常可以得到想要的結果。 http://jsfiddle.net/3TBVc/9/似乎在Android上適合我。輸入字段可能會吃一些'拖'事件(在Android上),但它的功能。 – 2012-04-10 20:55:07

+0

它仍然在我的Android設備上觸發點擊事件(並且還在iPhone上顯示第一個按鈕)。 – 2012-04-12 07:50:56

2

我做了一個解決方案我自己,因爲我還沒有找到足夠的解決方案在別處:

var isTouch = ('ontouchstart' in window); 

    function kill(type){ 
    window.document.body.addEventListener(type, function(e){ 
     e.preventDefault(); 
     e.stopPropagation(); 
     return false; 
    }, true); 
    } 

    if(isTouch){ 
    kill('mousedown'); 
    kill('mouseup'); 
    kill('click'); 
    kill('mousemove'); 
    } 

isTouch的檢查可讓鼠標輸入設備正常工作,但會殺死Safari/iOS上的仿真事件。訣竅是在addEventListener的調用中使用useCapture = true,這樣我們就可以在頁面中獲取所有鼠標事件,而不會在整個Web應用程序中黑屏代碼。請參閱該文檔在這裏的功能:https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener?redirectlocale=en-US&redirectslug=DOM%2Felement.addEventListener

編輯:

現在處理這個問題庫是更好的,你可以使用類似Fastclick作爲替代(https://github.com/ftlabs/fastclick)。

+4

當您知道設備是觸摸或鼠標輸入時,這是一個很好的解決方案。但是當你擁有Windows 8筆記本電腦/平板電腦之類的東西時,你需要做其他事情。 – psayre23 2013-07-20 19:16:02

+0

我們的解決方案是監聽click和touchstart/stop/move事件,並且只在'ontouchstart'不可用時註冊點擊事件。移動Safari瀏覽器同時註冊觸摸和點擊事件,但該方法僅在該情況下注冊觸摸事件。另外,我們可以不考慮mousemove事件。 – 2014-03-03 23:38:22

+1

被拒絕,因爲如果觸摸事件可用,問題不是完全禁用鼠標事件... – iRaS 2014-10-26 15:47:19

2

如果您有支持它同時支持鼠標和觸摸設備,另一種解決方案是使用捕獲事件監聽器停止觸摸事件之後發生的任何

  • 延遲鼠標在整個事件
  • 在相同的位置相同的目標元件上的觸摸事件
  • 作爲觸摸EV的觸摸事件

的信息(時間,位置或目標元件) ent可以記錄在另一個捕獲事件偵聽器中。

0

在Window.matchesMedia函數中包裝鼠標唯一的代碼是我找到的最乾淨的方法。

if (window.matchMedia('(hover: hover), (any-hover: hover), (-moz-touch-enabled: 0)').matches) { 
    el.addEventListener('mouseover', ev => { 
     // mouse handler, no simulated hover 
    } 
} 

這適用於防止模擬懸停,但也可能會阻止模擬點擊。

請注意:啓用-moz-觸摸到Firefox的需要作爲版本58