延遲的clickhtml
擁抱tapnode
一次觸碰android
阻止它們!!!preventDefault仍是stopPropagtiongit
模擬事件是什麼鬼web
事故現場編程
延遲bootstrap
點穿(包含angular的ng-click)瀏覽器
焦點獲取iphone
分析Yocto,zepto,fastclick帶來的思考組件化
zepto -- 萬惡的tap
fastclick -- 「完美」
Yocto -- 「後zepto時代替代者」
讓咱們開始吧!
遲到的click
「移動端最好用tap,click是有延遲的...」
開始寫移動端事件的時候就被告知了這一句真理,一直也沒放在心上,tap就tap吧。 可是忽然有一天很無聊,想要看看,到底爲何click有延遲,延遲多少。
咱們先來看兩張圖
*這裏的數據可能不許,由於屢次點擊的時間會不一樣,可是大概也就這樣-_-# 這裏注意到
1. click的時間基本固定在301ms
2. tap的時間會有點飄忽,差很少70-150ms左右。
爲何要給出這樣的數據呢,是爲了印證click確實是比tap慢的。網上基本比較一致的緣由是:
"iphone建立了雙擊縮放的標準,背後的實現是,在第一次的點擊時等待300ms,肯定下一次是否繼續點擊。而後被衆多移動端瀏覽器商家紛紛模仿 -----我亂說的"
這就是click有300ms延遲的緣由
既然咱們知道了是因爲縮放引發的延遲,那麼咱們加入熟悉的
<meta name="viewport" content="width=device-width user-scalable=no">
再看一下數據,發現延遲果真沒有了,速度和tap一毛同樣(真是睜着眼說瞎話啊...)。
然而user-scalble=no 是很是邪惡
的東西,咱們不能光靠這個去解決問題,所以咱們須要擁抱新同窗tap...
新同窗tap
tap事件運用最多莫過於zepto啦。看一片zepto的源碼好了。
這片代碼位於zepto.js最底部,由於篇幅縮短了swiper和dbclick的判斷,可是能夠看出,tap是基於touchstart和touchend模擬的(應該說別無他法)。
這就是tap比click快的緣由
一次觸碰
因爲歷史緣由,所以在移動端進行觸碰的時候,也會觸發鼠標的事件。這裏給出測試結果。 觸發的順序是:
touchstart
touchmove
touchend
mouseover
mouseenter
mousedown
click
整個觸碰過程當中,從touchstart開始,到click終結。
能夠看出tap和click的本質上其實只是觸碰的不一樣階段。
阻止它們!preventDefault仍是stopPropagation
既然zepto能夠本身建立一個tap事件,咱們是否是也能夠呢。考慮再三,難點在於怎麼將上面控制一次觸碰
的流程,因爲不知道這些事件是具備上下級(是否冒泡)
仍是 傳遞性質
。 (後來發現本身腦洞略大,爲何會這麼想呢...TAT)
在web端,preventDefault最經常使用的場景莫過於 a連接
和 submit按鈕
。 由於preventDefault的定義是
「取消事件的默認行爲。若是cancelable是true,則可使用這個方法。」
而stopPropagation的定義是
「取消事件的進一步捕獲或冒泡,若是bubbles爲true,則可使用這個方法。」
那麼在移動端,若是想要改變一次觸碰
的的流程,究竟是阻止默認行爲
,仍是冒泡
呢。
這裏上一個demo的截圖
通過測試,發現stopPropagation並不能阻止click的觸發,而preventDefault被證明在確實是無解的大招
。
這裏插入一個知識點:stopImmediatePropagation是一個很屌的方法,不只可以阻止事件冒泡,並且可以阻止綁定在同一個[事件名稱]上的全部後續事件觸發。
stopImmeadiatePropagation的demo傳送門
阻止移動端的觸碰默認行爲。preventDefault是有着絕對的做用的。
模擬事件是什麼鬼
在web端模擬一個事件已是很成熟啦,好處一堆,便於測試,分離代碼,組件化等等...咱們是否可以應用在移動端呢。 先看到模擬事件分爲如下四種
UIEvents
MouseEvents
MutationEvents
HTMLEvents
流程大概分爲
建立Event
初始化Event
觸發Event
觸發以後就和正常流程觸發的事件別無二致啦。這裏給出一個<<高級編程>>的典型點擊
demo。後面咱們要用到這個demo去作一些很酷的事情!
事故現場
延遲
前面說過了,點擊延遲主要由於不肯定是否進行縮放致使的,可是user-scalable
並非什麼靈丹妙藥,因而咱們擁抱了tap,用touch-start
和touch-end
模擬了一個輕觸tap事件,使得點擊看起來快速了不少。典型表明就是zepto的tap事件。
解決方案:
假如應用場景不復雜(沒有滑動,獲取焦點)
,咱們能夠很是簡單模擬一個閹割版的點擊,並且也同時避免了點穿。如圖
點穿
大部分用zepto的同窗必定踩過這個坑。
「zepto竟然把事件都綁定在document上!這太坑了。」
呵呵,反正踩完坑就開始一頓亂噴,可是問題仍是沒有解決,若是要簡單解決單純的點擊
和上面同樣,加上霸道的e.preventDefault()
阻止默認事件傳遞就行了。可是咱們用zepto還用了swiper,閹割版的作法還會致使一系列問題。因而乎號稱完美
的fastclick閃亮登場了。
可是同樣是把事件綁定在document上,爲何fastclick就不坑了呢。
呵呵。
解決方案:
fastclick (FT Labs,目前GitHub已經10000
星星了.....)
Yocto(基於zepto的支付寶移動端庫)
模擬fastclick作法,加入到本身豪華午飯裏^_^
然而
在使用angular的時候,無可避免必定會用到ng-click
(誰說無可避免,不是還有ng-touch這樣的類庫嗎 逃...)
那麼不用類庫,直接了當解決ng-click點穿怎麼是好。
然而-解決方案:
古語有云:用angular的都是屌絲,屌絲通常都用了user-scalable=no
,因此click速度不擔憂...
只須要在ng-click=fn($event
),傳入event就又可使用大招event.preventDefault
然而更合理的作法應該是這樣的。
傳送門:關於angular自定義touchstart無效的解決辦法
事已至此,點穿就解決了。(啦啦啦啦啦啦啦)
焦點獲取
點穿以後,無非就是焦點獲取錯誤或者觸發了其餘表單元素,因此咱們也必須處理一下這些邊角料。
這裏列一下坑
textarea
須要focus
的
selct
(這個天坑啊 android須要click
IOS須要focus
)
input
(file,image,radio,checkbox) 須要click
label
(*通常不操做,可是友好的作法是聚焦到對應的input
)
所以作法是,設置一個標誌量needFocus,在觸碰
的過程當中判斷target
是否爲須要focus
的,是就取消點擊,改成聚焦
。
一、獲取target類型
target.nodeName.toLowerCase();二、聚焦
target.focus()三、聚焦在label對應的input
document.getElmentById(labelElement.htmlFor).focus()
fastclick
這裏簡單說一下fastclick的解決點穿的原理
fastclick綁定在document.body上,檢查一次觸碰
的全部事件
用touchstart-touchend模擬了tap,而是在阻止真實的click觸發後,模擬了真實click
到點擊對象
上。從而快速又完整的完成一次點擊,而且不點穿。
fastclick依然對雙擊事件作
了保留,作法是,在touchend判斷是否處於上次點擊的時間範圍內(fastclick出的是200ms)
fastclick沒有放棄swipe
,中間加入了touchmove,使用了移動的範圍(fastclick給出的是10)來判斷是否進行滑動。
fastclick對label
和select
作了很是細緻的處理(萬星項目呢,開玩笑呢!)
上面說的很複雜,僞代碼表示一下
var lastClickTime,trackClick; // 上一次點擊時間,和是否追蹤點擊btn.bind("touchstart",function(e){
// 判斷是否用戶快速雙擊事件,若是是,禁止本次觸碰後續操做(包括模擬點擊事件) trackClick = true;
if(e.timeStamp - lastClickTime < 200){
e.preventDefault();
} },false);btn.bind("touchmove",function(e){
// 判斷是否移動過大致使偏移原標 或者 移動超出必定範圍(這裏是) if(moveToAnotherTarget || moveTooMuch){
trackClick = false;
}},false);btn.bind("touchend",function(e){
// 依然進行是否[追蹤]和[雙擊]判斷,這裏省略...
// 這裏判斷進行[焦點]仍是[下拉菜單]仍是須要[點擊] // 這裏按照點擊來進行,先禁用原生的點擊,再把模擬的點擊事件發送給當前目標 e.preventDefault();
// 這裏就是模擬事件發揮的地方了 e.target.dispatch(mouseClickEvent);},false);
其實fastclick的核心就是[e.preventDefault阻止真實click]
和[分發模擬鼠標事件的click]
。#我亂說的#
Yocto
雖然名爲支付寶下的[超輕]移動類庫,這裏仍是想像成一個維護快速的zepto會比較好。 作法和fastclick同樣。看一下他們更新的issue#
那既然有fastclick,爲何要看Yocto呢。
一、 zepto+fastclick顯得很不必二、 [輕]能夠獨立引用yocto-event.js三、 基於zepto,學習成本低
傳送門:yocto對於修改zepto的最佳實踐
目前這個項目的gitlab外人時看不到的,因此只能等待他們徹底開源了,以前看無線的移動端優化建議曾經提到,所以留心了一下,出來以後又能夠猛偷了...(讀書人的事情怎麼能叫偷 逃...)
到這裏,差很少恰好20分鐘,文章也結束了。
ps
:FastClick源碼比較短,這裏簡單作個引讀好了,但願不要誤人子弟(掩面...
fastclick = {
標誌變量, // 一堆輔助判斷觸碰類型的變量
核心方法:{ // 這些就是核心精華啊...10000個星星都在這裏了 onTouchStart
onTouchMove
onTouchEnd
onClick
onMouse
focus }
用戶定義方法:{
needClick, // 用戶決定最終行爲 needFocus // 用戶決定最終行爲 }
難點:{
updateScrollParent,// 對滑動進行了細緻的兼容,實現比較複雜 stopImmediate方法 // 對不兼容此方法的環境改變了事件定義方式 }}
參考文章:
移動端頁面touch會穿透,這是bug麼?
yocto的點穿demo
完全解決tap「點透」,提高移動端點擊響應速度
用bootstrap的同窗,手機點擊問題:很多朋友反饋在手機瀏覽器中沒法點擊下拉菜單的連接,搜索了一番,打開 bootstrap.min.js,查找到 ontouchstart ,替換爲 disable-ontouchstart 就能夠了。