衆所周知,移動端在處理點擊事件的時候,會有300毫秒的延遲。偏偏是這300毫秒的延遲,會讓人有一種卡頓的體驗。javascript
這300毫秒的緣由,在於早期瀏覽器的實現中,瀏覽器不知道用戶觸摸後,到底想作什麼,因此故意等待300毫秒,再觸發click事件。html
既然咱們已經知道了緣由了,怎麼解決呢?java
由於瀏覽器對click事件的處理,有300ms的延遲,而touchstart幾乎是當即執行的,估將全部click事件的監聽,改成touchstart事件的監聽,便可消除這300ms的延遲。瀏覽器
但這樣反作用也很大,移動端的交互體驗全靠觸摸,touchstart將會干擾其餘交互行爲的處理,例如滾動、拖拽等。this
既然瀏覽器有這300ms的延遲,那麼咱們來代替瀏覽器判斷,手動觸發click事件,這也是fastClick的解決方案。spa
fastClick的核心代碼prototype
FastClick.prototype.onTouchEnd = function(event){ // 一些狀態監測代碼 // 從這裏開始, if (!this.needsClick(targetElement)) { // 若是這不是一個須要使用原生click的元素,則屏蔽原生事件,避免觸發兩次click event.preventDefault(); // 觸發一次模擬的click this.sendClick(targetElement, event); } }
這裏能夠看到,FastClick在touchEnd的時候,在符合條件的狀況下,主動觸發了click事件,這樣避免了瀏覽器默認的300毫秒等待判斷。爲了防止原生的click被觸發,這裏還經過event.preventDefault()屏蔽了原生的click事件。code
咱們來看看他是怎麼模擬click事件的htm
FastClick.prototype.sendClick = function(targetElement, event) { // 這裏是一些狀態檢查邏輯 // 建立一個鼠標事件 clickEvent = document.createEvent('MouseEvents'); // 初始化鼠標事件爲click事件 clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); // fastclick的內部變量,用來識別click事件是原生仍是模擬 clickEvent.forwardedTouchEvent = true; // 在目標元素上觸發該鼠標事件, targetElement.dispatchEvent(clickEvent);
咱們在網上搜索fastClick,大部分都在說他解決了zepto的點擊穿透問題,他是怎麼解決的呢?就是上面最後一句,他模擬的click事件是在touchEnd獲取的真實元素上觸發的,而不是經過座標計算出來的元素。事件
最後,原理雖簡單,但仍是建議你們直接用FastClick而不是本身再實現一個。由於,你看他源碼裏面的註釋,有不少特殊狀況的補丁的,本身實現一個精簡版不免會漏這漏那。
同步發表於個人博客