摘要:前言本次給大家分享的是常見的移動端單點觸摸事件的設計思路及實踐。實現(xiàn)即手指滑動事件,應用場景如輪播圖左右滑動切換,整屏頁面滑動翻頁等,算是移動端最常見的手勢之一了。
前言
本次給大家分享的是常見的移動端單點觸摸事件的設計思路及實踐。
核心技術主要就是利用移動端的以下3個觸摸事件,來模擬和實現(xiàn)自定義的手勢操作
touchstart:手指觸摸到屏幕的一瞬間觸發(fā)
touchmove:手指在屏幕上移動時觸發(fā)
touchend:手指從屏幕上離開時觸發(fā)
概念梳理touch事件觸發(fā)時,有3組數(shù)據(jù)可以獲得觸摸信息,可能大家會對這幾組數(shù)據(jù)有些混淆,我根據(jù)自己的理解來盡量用通俗的語言給大家解釋清楚
touches:整個屏幕上所有的觸摸點集合
targetTouches:當前DOM元素上的所有觸摸點集合
changedTouches:相對上一次觸摸點發(fā)生變化的集合
我們先來看一張圖
如圖所示,我們在節(jié)點B上綁定touch事件,圓圈代表觸摸點。
此時節(jié)點B有3個觸摸點,即targetTouches數(shù)組有3項,分別儲存著觸摸點的信息,此時touches和targetTouches是相同的。
當我們將手指3移出節(jié)點B(始終保持3個手指觸摸在屏幕上),那么touchmove事件觸發(fā),targetTouches只剩2項,而touches依然有3項,此時changedTouches只有一項(因為只有手指3改變了)。
然后我們讓所有手指離開屏幕,那么此時touchend事件觸發(fā),touches只剩0項,targetTouches剩0項,changedTouches有3項(因為3個手指發(fā)生了變化)。
好了,理解這些概念,有助于我們理解代碼中何時改去哪個touch數(shù)組里面的值。
思路及實踐 taptap可以理解為點擊事件,和click不同的是,移動端的click事件有大約300ms的延遲,這是因為瀏覽器要判斷是否為雙擊事件。
思路
touchstart:時記錄時間點以及觸摸點的x、y坐標
touchend:計算此時與開始時的時間差,水平和垂直方向的偏移量
說明:時間差用來判斷用戶觸摸的時長,超過規(guī)定時間則tap事件無效;偏移量用來判斷用戶的觸摸事件內(nèi)是否有過移動的痕跡,這里我們允許少量的偏移,因為手指可能出現(xiàn)抖動的情況
實現(xiàn)
const tapDefaults = { time: 250, offset: 10 } export default function tap (node, a, b) { let st, sx, sy let opts, callback if (typeof a === "function") { callback = a opts = Object.assign({}, tapDefaults, b) } else { callback = b opts = Object.assign({}, tapDefaults, a) } node.addEventListener("touchstart", (e) => { e.preventDefault() // 組織瀏覽器默認行為,防止觸摸過程頁面滾動 const touch = e.targetTouches[0] st = e.timeStamp sx = touch.pageX sy = touch.pageY }, false) node.addEventListener("touchend", (e) => { const touch = e.changedTouches[0] if ( // 若為長按,則將時間判定條件更改 e.timeStamp - st <= opts.time && Math.abs(touch.pageX - sx) <= opts.offset && Math.abs(touch.pageY - sy) <= opts.offset ) { callback && callback() } }, false) }doubletap
即雙擊事件,兩次點擊時間間隔不超過規(guī)定時間則視為有效。
思路
第一次有效點擊,記錄該狀態(tài),反之重置狀態(tài)
第二次有效點擊,觸發(fā)事件并重置狀態(tài)
若兩次時間間隔過長,重置狀態(tài)
實現(xiàn)
const tapDefaults = { time: 250, offset: 10 } function handler (node, inject) { let st, sx, sy node.addEventListener("touchstart", (e) => { e.preventDefault() const touch = e.targetTouches[0] st = e.timeStamp sx = touch.pageX sy = touch.pageY }, false) node.addEventListener("touchend", (e) => { const touch = e.changedTouches[0] inject({ time: e.timeStamp - st, offsetX: Math.abs(touch.pageX - sx), offsetY: Math.abs(touch.pageY - sy) }) }, false) } export function doubletap (node, a, b) { let opts, callback let status = 0 if (typeof a === "function") { callback = a opts = Object.assign({}, tapDefaults, b) } else { callback = b opts = Object.assign({}, tapDefaults, a) } handler(node, (info) => { if ( info.time <= opts.time && info.offsetX <= opts.offset && info.offsetY <= opts.offset ) { if (status === 0) { status = 1 // 時間間隔太長則重置狀態(tài) setTimeout(() => { status = 0 }, opts.time) } else if (status === 1) { callback && callback() status = 0 } } else { status = 0 } }) }longtap
即長按,手指按住超過規(guī)定時間視為有效,在手指離開時觸發(fā)。
思路
和tap事件思路一樣,只不過時間的判定條件變更一下,改為超過多長時間才觸發(fā)
實現(xiàn)
const longtapDefaults = { time: 350, offset: 10 } // 這里代碼邏輯和tap事件一樣 // 更改時間判定為: // e.timeStamp - st > opts.timepress
即按壓事件,按住超過規(guī)定時間自動觸發(fā),注意和longtap不同的是,longtap需要等到手指離開時觸發(fā),而press在按壓時間達到規(guī)定值,自動觸發(fā),此時手指還在屏幕上。
思路
touchstart:記錄此時的x、y坐標,并且開啟一個定時器,在規(guī)定時間后執(zhí)行回調(diào),默認是350ms
touchmove:監(jiān)聽移動過程,在事件觸發(fā)前,若出現(xiàn)偏移量過大,則取消定時器
touchend:取消定時器
分析:根據(jù)以上思路,若按壓時間短,則手指離開時定時器已取消,回調(diào)不會觸發(fā)。
實現(xiàn)
const pressDefaults = { time: 350, offset: 10 } export default function press (node, a, b) { let opts, callback, sx, sy let timer = null if (typeof a === "function") { callback = a opts = Object.assign({}, pressDefaults, b) } else { callback = b opts = Object.assign({}, pressDefaults, a) } node.addEventListener("touchstart", (e) => { e.preventDefault() const touch = e.targetTouches[0] sx = touch.pageX sy = touch.pageY timer = setTimeout(() => { callback && callback() }, opts.time) }, false) node.addEventListener("touchmove", (e) => { const touch = e.targetTouches[0] if ( Math.abs(touch.pageX - sx) > opts.offset || Math.abs(touch.pageY - sy) > opts.offset ) { clearTimeout(timer) } }, false) node.addEventListener("touchend", () => { clearTimeout(timer) }, false) }swipe
即手指滑動事件,應用場景如:輪播圖左右滑動切換,整屏頁面滑動翻頁等,算是移動端最常見的手勢之一了。
思路
touchstart:記錄時間點和觸摸點位置
touchmove:實時判斷滑動偏移量
touchend:計算滑動速度和方向,條件判定是否觸發(fā)事件
分析:考慮到需要在滑動過程做一些動畫特效等操作,因此我們將滑動中的事件暴露給用戶自定義,值得注意的是,若是要實時改變滑塊位置的話,最好不要截流或防抖,截流會造成滑動卡頓的現(xiàn)象,而防抖會出現(xiàn)延遲同步滑動操作的情況;另外對滑動速度也進行了處理,原則上用戶滑動距離超過規(guī)定后即視為有效,然而為了更好的用戶體驗,我們判定,如果用戶在短時間內(nèi)滑動速度非常快的話,也視為一次有效的操作,不一定非要滑動很長的距離
實現(xiàn)
const swipeDefaults = { direction: "horizontal", // vertical speed: 200, offset: 100, prevent: true, // touchmove: (offset) => {} } export default function swipe (node, a, b) { let opts, callback, sTime, sTouch, eTouch if (typeof a === "function") { callback = a opts = Object.assign({}, swipeDefaults, b) } else { callback = b opts = Object.assign({}, swipeDefaults, a) } node.addEventListener("touchstart", (e) => { if (opts.prevent) { e.preventDefault() } sTime = e.timeStamp sTouch = eTouch = e.targetTouches[0] }, false) if (typeof opts.touchmove === "function") { node.addEventListener("touchmove", (e) => { eTouch = e.targetTouches[0] if (opts.direction === "horizontal") { opts.touchmove(eTouch.pageX - sTouch.pageX) } else { opts.touchmove(eTouch.pageY - sTouch.pageY) } }, false) } node.addEventListener("touchend", (e) => { eTouch = e.changedTouches[0] let time = e.timeStamp - sTime let offset, direction if (opts.direction === "horizontal") { offset = eTouch.pageX - sTouch.pageX direction = offset > 0 ? "right" : "left" } else { offset = eTouch.pageY - sTouch.pageY direction = offset > 0 ? "down" : "up" } if ( Math.abs(offset) >= opts.offset || Math.abs(offset) / time * 1000 >= opts.speed ) { callback && callback(direction) } }, false) }結(jié)束語
通過以上的思路講解和代碼實現(xiàn),我們完成了一個單點觸控的移動端手勢庫,是不是迫不及待的想要一睹為快、體驗一番。
最后附上本次分享的源碼和文檔:https://github.com/ansenhuang/axe/blob/master/packages/touch/README.md
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/93723.html
摘要:中手勢原理分析與數(shù)學知識的實踐引言在這觸控屏的時代,人性化的手勢操作已經(jīng)深入了我們生活的每個部分。這篇博文主要是解析了移動端常用手勢的原理,及從前端的角度學習過程中所使用的數(shù)學知識。 HTML5中手勢原理分析與數(shù)學知識的實踐 引言 在這觸控屏的時代,人性化的手勢操作已經(jīng)深入了我們生活的每個部分。現(xiàn)代應用越來越重視與用戶的交互及體驗,手勢是最直接且最為有效的交互方式,一個好的手勢交互,能...
摘要:去年年底自己搭了一個在移動端的開發(fā)框架,感覺體驗不是很好。路由懶加載首頁終于寫完了,以上這些就是我在移動端體驗優(yōu)化的實戰(zhàn)。去年年底自己搭了一個vue在移動端的開發(fā)框架,感覺體驗不是很好。上個星期又要做移動端的項目了。所以我花了兩天時間對之前的那個開發(fā)框架做了以下優(yōu)化 自定義vuex-plugins-loading 路由切換動畫 + keep alive 動態(tài)管理緩存組件 better-sc...
摘要:單點手勢庫分析手勢是什么有哪些方法實現(xiàn)首先我這里指的手勢是指我們在移動端進行觸屏交互的時候,用戶操作的一些手勢。可以看地址總結(jié)這是我挺久之前做的移動端單點手勢庫學習時參考劇中人你可以在這里找到我個人網(wǎng)站 單點手勢庫 分析 手勢是什么? 有哪些方法實現(xiàn)? 首先我這里指的手勢是指我們在移動端進行觸屏交互的時候,用戶操作的一些手勢。在我們在移動端需要一些交互的時候。難免有時候需要左滑右...
摘要:單點手勢庫分析手勢是什么有哪些方法實現(xiàn)首先我這里指的手勢是指我們在移動端進行觸屏交互的時候,用戶操作的一些手勢。可以看地址總結(jié)這是我挺久之前做的移動端單點手勢庫個人博客地址學習時參考劇中人 單點手勢庫 分析 手勢是什么? 有哪些方法實現(xiàn)? 首先我這里指的手勢是指我們在移動端進行觸屏交互的時候,用戶操作的一些手勢。在我們在移動端需要一些交互的時候。難免有時候需要左滑右滑。 目前市面...
閱讀 3722·2021-10-13 09:39
閱讀 3788·2021-09-24 09:48
閱讀 1188·2021-09-01 10:30
閱讀 2525·2019-08-30 15:55
閱讀 1773·2019-08-29 16:39
閱讀 2294·2019-08-26 13:55
閱讀 3048·2019-08-26 12:23
閱讀 1632·2019-08-26 11:59