fastclick 關於輸入框的填坑小記
之前筆者碰到了一個與輸入框有關的 bug,具體現象是在某些 iOS 手機上,輸入框只能 focus 一次,一旦 blur 就無法再次點選 focus 了,於是去百度了一下(勿噴),搜到了被各路部落格"借鑑"最多的手 Q 同學之前發表的一篇文章《FastClick 填坑及原始碼解析》,一頓無腦複製貼上驗證 ok 先上線。週末再翻了下 fastclick 的原始碼以及那篇文章,好像有哪裡不太對勁...
首先還是先看下我們為什麼要用 fastclick,拿 input 來說,原生的點選事件在 touchEnd 與 foucs 之間會有 300ms 的延遲,當然在 WKWebView 下設定 user-scalable = 0 可以解決
但是世界並沒有那麼美好,很多 APP 仍是 UIWebView,所以避免被使用者 diss 還是要通過第三方庫來解決。fastclick 登場,既然原生的 focus 要等,fastclick 就攔截了原生的事件,同時主動觸發後續事件,"攔截"、"觸發"主要就是幹了這麼兩件事
看似完美解決,各種相容性的坑還是存在的,這裡二次觸發 focus 就翻了車。上面的 onTouchEnd 是原始碼裡的處理函式,可以看到在內部主動觸發了 focus,並通過 preventDefault 攔截了後續原生的 foucs、click 事件;下面是手 Q 同學的解決方法,在後面加了一個對輸入框的判斷,如果是輸入框就不作 preventDefault 處理,並在文章解釋道"由於 preventDefault 導致無法觸發 focus"
等等,我們是不是忘了 fastclick 是幹嘛的了,回顧下前文,"攔截"、"觸發",不執行 preventDefault 的話流程便如下圖。在手動觸發 focus 失敗的情況下,過了 300ms 原生的 focus 事件觸發,但是 click 事件是不是執行了兩次呢,所以這個問題的解決反向是為什麼手動觸發的 focus 沒有生效
主動觸發的 focus 為什麼第二次點選就不執行了呢,看下原始碼 focus 的函式。如果是 iOS 系統,通過 setSelectionRange 來間接觸發 focus,這麼做是為了解決其他相容性的問題,所以是有必要的,但是通過瘋狂 console 發現,這個 setSelectionRange 在我本人的手機上(iOS 11.4 / WKWebview)只會間接觸發一次 focus。具體是系統版本還是 webView 的問題,有待進一步驗證
於是改了兩行程式碼,無論 setSelectionRange 能不能觸發 focus,都補一次 focus,看起來好像有點問題,這樣會不會觸發兩次 focus?實驗一下,不會,不會像 click 那樣觸發多次,初步結論是在一個事件週期中 focus 有且只會生效一次
本文中不確定、不準確的結論歡迎在評論中及時 diss