Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: useSwipe #2337

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: useSwipe
SnowingFox committed Oct 17, 2023
commit d5ada1900da4d926ddd6eed67179529a3957852f
1 change: 1 addition & 0 deletions config/hooks.ts
Original file line number Diff line number Diff line change
@@ -100,6 +100,7 @@ export const menus = [
'useScroll',
'useSize',
'useFocusWithin',
'useSwipe',
],
},
{
82 changes: 81 additions & 1 deletion packages/hooks/src/useSwipe/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,81 @@
export default function useSwipe() {}
import type { UseSwipeDirection, UseSwipeOptions, UseSwipeReturn } from './types';
import type { MutableRefObject } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { useMount, useUnmount } from 'ahooks';

export default function useSwipe(
elRef: MutableRefObject<HTMLElement>,
options: UseSwipeOptions = {},
): UseSwipeReturn {
const [isSwiping, setIsSwiping] = useState(false);
const [coordsStart, setCoordsStart] = useState({ x: 0, y: 0 });
const [coordsEnd, setCoordsEnd] = useState({ x: 0, y: 0 });

const diffX = useMemo(() => coordsStart.x - coordsEnd.x, [coordsStart.x, coordsEnd.y]);
const diffY = useMemo(() => coordsStart.y - coordsEnd.y, [coordsStart.y, coordsEnd.y]);

const { abs } = Math;

const direction = useMemo<UseSwipeDirection>(() => {
if (abs(diffX) > abs(diffY)) {
return diffX > 0 ? 'left' : 'right';
} else {
return diffY > 0 ? 'up' : 'down';
}
}, [diffX, diffY]);

const getTouchEventCoords = (e: TouchEvent) => [e.touches[0].clientX, e.touches[0].clientY];

const updateCoordsStart = (e: TouchEvent) => {
const [x, y] = getTouchEventCoords(e);
setCoordsStart({ x, y });
};

const updateCoordsEnd = (e: TouchEvent) => {
const [x, y] = getTouchEventCoords(e);

setCoordsEnd({ x, y });
};

const touchStartListener = useCallback((event: TouchEvent) => {
updateCoordsStart(event);
updateCoordsEnd(event);
options.onSwipeStart?.(event);
setIsSwiping(true);
}, []);

const touchMoveListener = useCallback((event: TouchEvent) => {
options.onSwipe?.(event);
updateCoordsEnd(event);
}, []);

const touchEndListener = useCallback((event: TouchEvent) => {
options.onSwipeEnd?.(event, direction);
setIsSwiping(false);
}, []);

useMount(() => {
const el = elRef.current;

el.addEventListener('touchstart', touchStartListener);

el.addEventListener('touchmove', touchMoveListener);

el.addEventListener('touchend', touchEndListener);
});

useUnmount(() => {
const el = elRef.current;

el.removeEventListener('touchstart', touchStartListener);
el.removeEventListener('touchmove', touchMoveListener);
el.removeEventListener('touchend', touchEndListener);
});

return {
isSwiping,
direction,
lengthX: diffX,
lengthY: diffY,
};
}
60 changes: 60 additions & 0 deletions packages/hooks/src/useSwipe/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
export type UseSwipeDirection = 'up' | 'down' | 'left' | 'right' | null;

export interface UseSwipeOptions {
/**
* 检测滑动的方向
* 如果不传direction的话就是默认用户自己实现swipe的direction
* 如果传了direction我们hook内部就自动帮用户检测
*/
direction?: UseSwipeDirection;

/**
* Register events as passive
*
* @default true
*/
passive?: boolean;

/**
* 检测的阈值
* @default 50
*/
threshold?: number;

/**
* 滑动开始时调用
*/
onSwipeStart?: (e: TouchEvent) => void;

/**
* 滑动时调用
*/
onSwipe?: (e: TouchEvent) => void;

/**
* 滑动结束后调用
*/
onSwipeEnd?: (e: TouchEvent, direction: UseSwipeDirection) => void;
}

export interface UseSwipeReturn {
/**
* 是否在滑动
*/
isSwiping: boolean;

/**
* 滑动的 x 轴距离
*/
lengthX: number;

/**
* 滑动的 y 轴距离
*/
lengthY: number;

/**
* 滑动的方向
*/
direction: UseSwipeDirection;
}
6,085 changes: 3,007 additions & 3,078 deletions pnpm-lock.yaml

Large diffs are not rendered by default.