前端開發之tap點透淺談

zepto的tap事件點透問題分析:

一、點透是什么

你可能碰到過在列表頁面上創建一個彈出層,彈出層有個關閉的按鈕,你點了這個按鈕關閉彈出層后后,這個按鈕正下方的內容也會執行點擊事件(或打開鏈接)。這個被定義為這是一個“點透”現象。
在前面的項目中遇到了如下圖的問題:在點擊彈出來的選擇組件的右上角完成后會讓完成后面的input輸入框聚焦,彈出輸入鍵盤,也就是點透了


技術分享

二、為什么會出現點透?

我們來看看zepto源碼里面看關于tap的實現方法:

(http://upload-images.jianshu.io/upload_images/1782900-f64f9813022596c6.gif?imageMogr2/auto-orient/strip) 1 $(document).ready(function(){ 2 var now, delta, deltaX = 0, deltaY = 0, firstTouch, _isPointerType 3 4 if (‘MSGesture‘ in window) { 5 gesture = new MSGesture() 6 gesture.target = document.body 7 } 8 9 $(document) 10 .bind(‘MSGestureEnd‘, function(e){ 11 var swipeDirectionFromVelocity = 12 e.velocityX > 1 ? ‘Right‘ : e.velocityX < -1 ? ‘Left‘ : e.velocityY > 1 ? ‘Down‘ : e.velocityY < -1 ? ‘Up‘ : null; 13 if (swipeDirectionFromVelocity) { 14 touch.el.trigger(‘swipe‘) 15 touch.el.trigger(‘swipe‘+ swipeDirectionFromVelocity) 16 } 17 }) 18 .on(‘touchstart MSPointerDown pointerdown‘, function(e){ 19 if((_isPointerType = isPointerEventType(e, ‘down‘)) && 20 !isPrimaryTouch(e)) return 21 firstTouch = _isPointerType ? e : e.touches[0] 22 if (e.touches && e.touches.length === 1 && touch.x2) { 23 // Clear out touch movement data if we have it sticking around 24 // This can occur if touchcancel doesn‘t fire due to preventDefault, etc. 25 touch.x2 = undefined 26 touch.y2 = undefined 27 } 28 now = Date.now() 29 delta = now - (touch.last || now) 30 touch.el = $(‘tagName‘ in firstTouch.target ? 31 firstTouch.target : firstTouch.target.parentNode) 32 touchTimeout && clearTimeout(touchTimeout) 33 touch.x1 = firstTouch.pageX 34 touch.y1 = firstTouch.pageY 35 if (delta > 0 && delta <= 250) touch.isDoubleTap = true 36 touch.last = now 37 longTapTimeout = setTimeout(longTap, longTapDelay) 38 // adds the current touch contact for IE gesture recognition 39 if (gesture && _isPointerType) gesture.addPointer(e.pointerId); 40 }) 41 .on(‘touchmove MSPointerMove pointermove‘, function(e){ 42 if((_isPointerType = isPointerEventType(e, ‘move‘)) && 43 !isPrimaryTouch(e)) return 44 firstTouch = _isPointerType ? e : e.touches[0] 45 cancelLongTap() 46 touch.x2 = firstTouch.pageX 47 touch.y2 = firstTouch.pageY 48 49 deltaX += Math.abs(touch.x1 - touch.x2) 50 deltaY += Math.abs(touch.y1 - touch.y2) 51 }) 52 .on(‘touchend MSPointerUp pointerup‘, function(e){ 53 if((_isPointerType = isPointerEventType(e, ‘up‘)) && 54 !isPrimaryTouch(e)) return 55 cancelLongTap() 56 57 // swipe 58 if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) || 59 (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) 60 61 swipeTimeout = setTimeout(function() { 62 touch.el.trigger(‘swipe‘) 63 touch.el.trigger(‘swipe‘ + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2))) 64 touch = {} 65 }, 0) 66 67 // normal tap 68 else if (‘last‘ in touch) 69 // don‘t fire tap when delta position changed by more than 30 pixels, 70 // for instance when moving to a point and back to origin 71 if (deltaX < 30 && deltaY < 30) { 72 // delay by one tick so we can cancel the ‘tap‘ event if ‘scroll‘ fires 73 // (‘tap‘ fires before ‘scroll‘) 74 tapTimeout = setTimeout(function() { 75 76 // trigger universal ‘tap‘ with the option to cancelTouch() 77 // (cancelTouch cancels processing of single vs double taps for faster ‘tap‘ response) 78 var event = $.Event(‘tap‘) 79 event.cancelTouch = cancelAll 80 touch.el.trigger(event) 81 82 // trigger double tap immediately 83 if (touch.isDoubleTap) { 84 if (touch.el) touch.el.trigger(‘doubleTap‘) 85 touch = {} 86 } 87 88 // trigger single tap after 250ms of inactivity 89 else { 90 touchTimeout = setTimeout(function(){ 91 touchTimeout = null 92 if (touch.el) touch.el.trigger(‘singleTap‘) 93 touch = {} 94 }, 250) 95 } 96 }, 0) 97 } else { 98 touch = {} 99 }100 deltaX = deltaY = 0101 102 })103 // when the browser window loses focus,104 // for example when a modal dialog is shown,105 // cancel all ongoing events106 .on(‘touchcancel MSPointerCancel pointercancel‘, cancelAll)107 108 // scrolling the window indicates intention of the user109 // to scroll, not tap or swipe, so cancel all ongoing events110 $(window).on(‘scroll‘, cancelAll)111 })112 113 ;[‘swipe‘, ‘swipeLeft‘, ‘swipeRight‘, ‘swipeUp‘, ‘swipeDown‘,114 ‘doubleTap‘, ‘tap‘, ‘singleTap‘, ‘longTap‘].forEach(function(eventName){115 $.fn[eventName] = function(callback){ return this.on(eventName, callback) }116 })

可以看出zepto的tap通過兼聽綁定在document上的touch事件來完成tap事件的模擬的,及tap事件是冒泡到document上觸發的。
再點擊完成時的tap事件(touchstart、touchend)需要冒泡到document上才會觸發,而在冒泡到document之前,用戶手的接觸屏幕(touchstart)和離開屏幕(touchend)是會觸發click事件的,因為click事件有延遲觸發(這就是為什么移動端不用click而用tap的原因。大概是300ms,為了實現safari的雙擊事件的設計),所以在執行完tap事件之后,彈出來的選擇組件馬上就隱藏了,此時click事件還在延遲的300ms之中,當300ms到來的時候,click到的其實不是完成而是隱藏之后的下方的元素,如果正下方的元素綁定的有click事件此時便會觸發,如果沒有綁定click事件的話就當沒click,但是正下方的是input輸入框(或者select選擇框或者單選復選框),點擊默認聚焦而彈出輸入鍵盤,也就出現了上面的點透現象。

三、點透的解決方法:

  • 方案一:引入fastclick
    github鏈接:https://github.com/ftlabs/fastclick
    引入fastclick.js,因為fastclick源碼不依賴其他庫,所以你可以在原生的js前直接加上
window.addEventListener( "load", function() {
  FastClick.attach(document.body);
}, false );

或者有zepto或者jqm的js里面加上

$(function() {
  FastClick.attach(document.body);
});
  • 方案二:用touchend代替tap事件,并阻止touchend默認行為preventDefault()
$("#cbFinish").on("touchend", function (event) { // 很多處理比如隱藏什么的
  event.preventDefault();
});
  • 方案三:延遲一定的時間(300ms+)來處理事件
$("#cbFinish").on("tap", function (event) {
  setTimeout(function(){
    //一些處理
  },320);
});

這種方法其實很好,可以和fadeInIn/fadeOut等動畫結合使用,可以做出過度效果。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容