- 為什么移動(dòng)端不用click
移動(dòng)端的click有300ms延遲的問題,在移動(dòng)端瀏覽器中,連續(xù)兩次點(diǎn)擊是縮放操作,所以在用戶點(diǎn)擊屏幕后,瀏覽器會檢查在300ms內(nèi)是否有另一次點(diǎn)擊,如果沒有則觸發(fā)click事件,所以移動(dòng)端不用click - 替換click的方案
1.使用touchstart
touch事件包括touchstart、touchend、touchmove等,簡單使用touchstart來替換click,但問題是,如果我想在同一對象上綁定一個(gè)單擊事件和一個(gè)滑動(dòng)事件怎么辦,這時(shí)候就會出現(xiàn)沖突。
2.使用tap事件
標(biāo)準(zhǔn)事件中沒有tap事件,tap事件是一些庫,如zepto,使用touch進(jìn)行封裝的,在touchstart、touchend時(shí)記錄時(shí)間、手指位置,在touchend時(shí)進(jìn)行比較,如果手指位置為同一位置且時(shí)間間隔較短,且過程中未曾觸發(fā)touchmove事件,則調(diào)用回調(diào)函數(shù)。
zepto用于判斷的關(guān)鍵代碼:
//延遲時(shí)間
if (delta > 0 && delta <= 250) touch.isDoubleTap = true;
//允許的偏移量
if (deltaX < 30 && deltaY < 30) {……}
不過300ms后還是會產(chǎn)生click事件,只是在該對象上沒有進(jìn)行監(jiān)聽,由此產(chǎn)生了“點(diǎn)透”現(xiàn)象:
(1)頁面彈出一個(gè)模態(tài)框,模態(tài)框上有個(gè)按鈕(關(guān)閉模態(tài)框),按鈕正下方(在主頁面上)有一個(gè)輸入框
(2)當(dāng)點(diǎn)擊模態(tài)框上的關(guān)閉按鈕,模態(tài)框立即消失,但300ms后click事件觸發(fā),而輸入框正好監(jiān)聽click事件,因此輸入框會得到焦點(diǎn)
為什么不對click進(jìn)行攔截呢?原因是zepto使用的是事件代理,元素上的touch事件冒泡到document上,在document的事件回調(diào)中執(zhí)行綁定在元素上的事件回調(diào),而在document上執(zhí)行preventDefault是不起作用的。
3.使用fastclick
fastclick也是使用事件委托(FastClick.attach(document.body, options);),但是冒泡到body上后,通過tap原理來判斷是否單擊,是則重新構(gòu)造一個(gè)點(diǎn)擊事件dispatch到原來的元素上,觸發(fā)元素上的綁定事件,由于在tap事件后觸發(fā)click,所以解決了延遲問題,并且300ms后,不再產(chǎn)生click事件,所以解決了”點(diǎn)透“問題。
FastClick.prototype.sendClick = function(targetElement, event) {
……
clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent(this.determineEventType(targetElement),
true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
clickEvent.forwardedTouchEvent = true;
targetElement.dispatchEvent(clickEvent);
};
到了這里,我們知道,最好的解決兼容PC和移動(dòng)端的點(diǎn)擊事件的辦法是引入fastclick。然而我現(xiàn)在想要實(shí)現(xiàn)的是各種觸摸事件——gg——既然要實(shí)現(xiàn)各種觸摸事件,那就暫時(shí)不考慮PC的問題,所以考慮使用hammer.js
hammer.js
使用hammer.js實(shí)現(xiàn)qq消息中拖出刪除畫面的效果
在vue中使用hammer.js
使用方法:
<div v-touch:panleft="onPanLeft" v-touch:panright="onPanRight">
事件對象
TouchEvent 是一類描述手指在觸摸平面(觸摸屏、觸摸板等)的狀態(tài)變化的事件。這類事件用于描述一個(gè)或多個(gè)觸點(diǎn),使開發(fā)者可以檢測觸點(diǎn)的移動(dòng),觸點(diǎn)的增加和減少,等等。
每 個(gè) Touch對象代表一個(gè)觸點(diǎn); 每個(gè)觸點(diǎn)都由其位置,大小,形狀,壓力大小,和目標(biāo) element描述。 TouchList 對象代表多個(gè)觸點(diǎn)的一個(gè)列表
1) TouchEvent
TouchEvent的屬性繼承了 UIEvent和 Event。
三個(gè)重要屬性:
TouchEvent.changedTouches: 一個(gè) TouchList 對象,包含了代表所有從上一次觸摸事件到此次事件過程中,狀態(tài)發(fā)生了改變的觸點(diǎn)的 Touch 對象。
TouchEvent.targetTouches: 一個(gè) TouchList 對象,是包含了如下觸點(diǎn)的 Touch 對象:觸摸起始于當(dāng)前事件的目標(biāo) element 上,并且仍然沒有離開觸摸平面的觸點(diǎn)。
TouchEvent.touches: 一 個(gè) TouchList 對象,包含了所有當(dāng)前接觸觸摸平面的觸點(diǎn)的 Touch 對象,無論它們的起始于哪個(gè) element 上,也無論它們狀態(tài)是否發(fā)生了變化。
2) TouchList詳解
只讀屬性:length返回這個(gè)TouchList中Touch對的個(gè)數(shù)。(就是有幾個(gè)手指接觸到了屏幕)
方法:item(index)返回TouchList中指定索引的Touch對象
3) Touch詳解

touch類事件
- 事件基礎(chǔ)
觸摸事件,有touchstart touchmove touchend touchcancel 四種之分
1.touchstart:手指觸摸到屏幕會觸發(fā)
當(dāng)用戶手指觸摸到的觸摸屏的時(shí)候觸發(fā)。事件對象的 target 就是touch 發(fā)生位置的那個(gè)元素。
2.touchmove:當(dāng)手指在屏幕上移動(dòng)時(shí),會觸發(fā)
當(dāng)用戶在觸摸屏上移動(dòng)觸點(diǎn)(手指)的時(shí)候,觸發(fā)這個(gè)事件。一定是先要觸發(fā)touchstart事件,再有可能觸發(fā) touchmove 事件。 3.touchmove 事件的target 與最先觸發(fā)的 touchstart 的 target 保持一致。touchmove事件和鼠標(biāo)的mousemove事件一樣都會多次重復(fù)調(diào)用,所以,事件處理時(shí)不能有太多耗時(shí)操作。不同的設(shè)備,移動(dòng)同樣的距離 touchmove 事件的觸發(fā)頻率是不同的。 有一點(diǎn)需要注意:即使手指移出了 原來的target 元素,則 touchmove 仍然會被一直觸發(fā),而且 target 仍然是原來的 target 元素。
4.touchend:當(dāng)手指離開屏幕時(shí),會觸發(fā)。
當(dāng)用戶的手指抬起的時(shí)候,會觸發(fā) touchend 事件。如果用戶的手指從觸屏設(shè)備的邊緣移出了觸屏設(shè)備,也會觸發(fā) touchend 事件。5.touchend 事件的 target 也是與 touchstart 的 target 一致,即使已經(jīng)移出了元素。
6.touchcancel:可由系統(tǒng)進(jìn)行的觸發(fā)(如電話接入或者彈出信息),比如手指觸摸屏幕的時(shí)候,突然電話來了,或者系統(tǒng)中其他打斷了touch的行為,則可以觸發(fā)該事件。