用TypeScript開發手勢庫 - (3)統一化Mouse和Touch事件
any-touch 一個手勢庫
往期目錄
用 TypeScript 開發手勢庫 - (1)web開發常用手勢有哪些?
用 TypeScript 開發手勢庫 - (2)web開發常用手勢有哪些?
簡單看下架構
實現輸入格式統一(input)
為了同時支援滑鼠和touch裝置, 我們第一步把2種裝置產生資料統一化, 統一化後的資料我們統一叫他input.
4個基礎,7個快捷
input包含11個欄位,4個基礎欄位,7個快捷欄位, 這些都是為下一步進行計算處理(computed)使用.
4個基礎欄位
input包含4個基礎欄位:eventType / point / changedPoints / nativeEvent, 接下來依次解釋.
eventType
eventType可以理解為輸入狀態, 如touchstart/mousedown對應 start , touchmove/mousemove對應 move , touchend/mouseleave對應 end , touchcancel對應 cancel , 總計4種狀態.
point
觸點資訊, 儲存當前觸點相對瀏覽器視窗左上角的座標(clientX, clientY), point是個陣列, 儲存當前的所有觸點.
changedPoints
發生變化的觸點資訊, 是個陣列, 儲存著 上一次觸點相對當前觸點發生變化 的觸點(初看有些繞, 如不明可留言.).
nativeEvent
如果是touch裝置, 那麼對應touchEvent, 滑鼠對應MouseEvent.
處理touchEvent
export default (event: TouchEvent): any => { const point = Array.from(event.touches).map(({clientX,clientY})=>({clientX,clientY})); const changedPoints = Array.from(event.changedTouches).map(({clientX,clientY})=>({clientX,clientY})); const eventType = event.type.replace('touch', ''); return { eventType, changedPoints, point, nativeEvent: event, }; };
處理mouseEvent
let prevPoints: { clientX: number, clientY: number }[]; let isPressed = false; // 預設MouseEvent中對type宣告僅為string export default (event: MouseEvent): BaseInput | void => { let { clientX, clientY, type, button } = event; const changedPoints = prevPoints || [{ clientX, clientY }]; let points = [{ clientX, clientY }]; prevPoints = [{ clientX, clientY }]; // 必須左鍵 if ('mousedown' === type) { if (0 === button) { isPressed = true; } else { return; } } if ('mousemove' === type) { if (!isPressed) return; } else if ('mouseup' === type) { if (isPressed) { points = []; } else { return; }; isPressed = false; } const MAP = { mousedown: 'start', mousemove: 'move', mouseup: 'end' }; return { eventType: <eventType>MAP[<'mousedown' | 'mousemove' | 'mouseup'>type], changedPoints, points, nativeEvent: event }; };
7個快捷欄位
快捷欄位均由基礎欄位簡單衍生而來, 僅為了使用方便而直接放在這.
pointLength
對應point陣列的長度.
changedPointLength
對應changedPoints的長度.
timestamp
當前時間戳.
target
繫結事件的元素.
currentTarget
觸發事件所在元素.
center
觸點座標, 如果是多點, 那麼對應多點的中心座標( getCenter函式原始碼 ).
x/y
對應center.x和center.y
isFirst
是否本輪識別週期的開始, 如果當前的 eventType 為start階段, pointLength和changedPointLength的長度相等, 那麼可以判定, 當前為開始.
isFinal
是否本輪識別週期的結束, 如果當前的 eventType 為end或者cancel階段, 且所有觸點均離開, 那麼判定為結束.
擴充套件欄位的原始碼比較長, 請移步至 倉庫 .
下期預告
下期我們會講解computed, 計算階段比較複雜, 設計到input的開始/前一個/當前狀態的計算, 大家可以提前預熱.