為什么使用FastClick
在移動(dòng)端H5開發(fā)過程中,關(guān)于點(diǎn)觸可能會(huì)遇到如下兩個(gè)問題:
- 手動(dòng)點(diǎn)擊與真正觸發(fā)
click事件會(huì)存在300ms的延遲 - 點(diǎn)擊穿透問題(點(diǎn)擊行為會(huì)穿透元素觸發(fā)非父子關(guān)系元素的事件)
延遲的存在時(shí)因?yàn)闉g覽器想知道你是否在進(jìn)行雙擊操作;而點(diǎn)擊穿透是因?yàn)?00ms延遲觸發(fā)時(shí)的副作用。而使用fastclick能很好的解決這個(gè)問題,增加使用者的體驗(yàn)。
可以不使用的場(chǎng)景
不必使用的瀏覽器環(huán)境如下:
- Android + Chrome >32
- Android + Chrome +
meta="user-scalable=no" - 部分黑莓手機(jī)環(huán)境(可略過)
- 部分WindowsPhone環(huán)境(可略過)
這部分的判斷在下面的方法中有體現(xiàn),如果當(dāng)前環(huán)境支持快速點(diǎn)擊,則FastClick會(huì)自動(dòng)跳過初始化。
FastClick.notNeeded = function(layer) { ... }
原理過程
如果完整的描述FastClick過程需要考慮多種場(chǎng)景的兼容,這里就描述一個(gè)按鈕點(diǎn)擊過程的處理,下面是用來描述的代碼:
// 業(yè)務(wù)代碼
var $test = document.getElementById('test')
$test.addEventListener('click', function () {
console.log('1 click')
})
// FastClick簡(jiǎn)單實(shí)現(xiàn)
var targetElement = null
document.body.addEventListener('touchstart', function () {
// 記錄點(diǎn)擊的元素
targetElement = event.target
})
document.body.addEventListener('touchend', function (event) {
// 阻止默認(rèn)事件(屏蔽之后的click事件)
event.preventDefault()
var touch = event.changedTouches[0]
// 合成click事件,并添加可跟蹤屬性forwardedTouchEvent
var clickEvent = document.createEvent('MouseEvents')
clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null)
clickEvent.forwardedTouchEvent = true // 自定義的
targetElement.dispatchEvent(clickEvent)
})
這里進(jìn)行過程說明:
1. 業(yè)務(wù)正常使用click綁定事件
2. 在document.body綁定touchstart和touchend
touchstart
用于記錄當(dāng)前點(diǎn)擊的元素targetElement;
touchend
- 阻止默認(rèn)事件(屏蔽之后的click事件)
- 合成click事件,并添加可跟蹤屬性forwardedTouchEvent
- 在targetElement上觸發(fā)
click事件 - targetElement上綁定的事件立即執(zhí)行,完成FastClick
3. 執(zhí)行業(yè)務(wù)自己的click事件
總結(jié)
以上就完成了模擬FastClick,是不是很簡(jiǎn)單。事件的執(zhí)行過程需要了解:touch事件先于mouse事件先于click執(zhí)行,因此可以在document.body上綁定事件用于監(jiān)聽點(diǎn)觸行為,根據(jù)需要模擬click觸發(fā)真正需要響應(yīng)的元素。
(完)