用TypeScript開發手勢庫 - (3)統一化Mouse和Touch事件

鐵皮飯盒發表於2019-03-24

https://github.com/383514580/any-touch

any-touch 一個手勢庫

往期目錄

用 TypeScript 開發手勢庫 - (1)web開發常用手勢有哪些?

用 TypeScript 開發手勢庫 - (2)web開發常用手勢有哪些?

不到30行, 用any-touch實現一個drawer

簡單看下架構

架構

實現輸入格式統一(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的開始/前一個/當前狀態的計算, 大家可以提前預熱.

compute

compute部分原始碼

相關文章