移動端的touch事件處理

簡要的探討一下移動端 touch 事件處理幾個坑,以及相應的簡單處理方法。git

click 穿透

假設有個彈出層,上面有個關閉的按鈕支持 touchend 觸發後關閉,若正好下方有個元素支持 click 事件,在彈出層關閉後將會在下方元素觸發 click 事件。這種效果確定不是咱們須要的,並且咱們沒法肯定合適會在上方出現一個支持 touch 的彈出層,因此我認爲最好的處理方式是禁用全部元素的 click 事件,相比 click 須要長達 1s 的觸發時間,使用 touchend 能夠得到更好的體驗。github

tap 事件的斷定

一個正確的 tap 事件應當知足一下條件:web

  1. 用戶手指從屏幕移開時觸發
  2. 不能在用戶移動手指時觸發(防止和滾動、拖拽事件的衝突)
  3. 多個手指同時觸摸屏幕時不能觸發
  4. 不該該觸發 click 事件

具體實現代碼能夠參考 tap-eventapp

使用原生的滾動事件

Android 4.0 如下是不支持原生的 webview 滾動的,因此只能使用 iscroll 之類的工具來模擬元素滾動。它的缺點就是有些過於的複雜,因此我仍是會在條件容許的狀況下使用原生的滾動。函數

啓用原生滾動只須要給外層元素加上樣式 -webkit-overflow-scrolling: touch; 便可,若是你的監聽函數比較佔用資源咱們能夠經過一個簡單的 buffer 函數來限制它的觸發間隔,例如:工具

function buffer(fn, ms) {
  var timeout;
  return function() {
    if (timeout) return;
    var args = arguments;
    timeout = setTimeout(function() {
      timeout = null;
      fn.apply(null, args);
    }, ms);
  }
}


document.querySelector('.scrollable').onscroll = buffer(onScroll, 100);

另外的建議就是不要在可滾動元素上使用陰影樣式(text-shadow 和 box-shadow),由於它們很是影響性能,並且看上去也不怎麼美觀。性能

還有須要注意的是若是你須要啓用apple-mobile-web-app-capable, 注意將apple-mobile-web-app-status-bar-style設置爲black-translucent,不然會出現還差 22 像素滾動不到頭的坑爹 bug。code

禁用頁面總體拖動

IOS下默認狀況下用戶的拖動操做在scroll滾到頭之後會致使總體頁面的滾動,一種方式是禁用掉 document 的 touchmove 原生觸發component

document.addEventListener('touchmove', function(e) {
  e.preventDefault();
});

此時原生的滾動是沒法工做的,解決辦法就是禁用滾動元素的 touchmove 事件冒泡事件

scrollable.addEventListener('touchmove', function (e) {
   e.stopPropagation();
});

另外一種方式是斷定滾動元素滾到頭以後禁用掉默認的處理

var el = document.querySelector('.scrollable');
var sy = 0;
events.bind(el, 'touchstart', function (e) {
  sy = e.pageY;
})

events.bind(el, 'touchmove', function (e) {
  var down = (e.pageY - sy > 0);
  //top
  if (down && el.scrollTop <= 0) {
    e.preventDefault();
  }
  //bottom
  if (!down && el.scrollTop >= el.scrollHeight - el.clientHeight) {
    e.preventDefault();
  }
})

我我的傾向於第二種方案,由於若是單純的禁用 document 的 touchmove 監聽,會致使一些處理的失效,好比說上面提到的 tap-event 模塊。

拖動方向與距離

經過 event 的 pageX 和 pageY 屬性便可計算,可參考 hammer.js

相關文章
相關標籤/搜索