Skip to content

Commit 61ac006

Browse files
committed
fix: 修改 useLonePress 在特殊设备、特殊情况下长按事件不触发问题
1 parent 6401a6b commit 61ac006

File tree

1 file changed

+85
-34
lines changed

1 file changed

+85
-34
lines changed

packages/hooks/src/useLongPress/index.ts

Lines changed: 85 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,6 @@ export interface Options {
1313
onLongPressEnd?: (event: EventType) => void;
1414
}
1515

16-
const touchSupported =
17-
isBrowser &&
18-
// @ts-ignore
19-
('ontouchstart' in window || (window.DocumentTouch && document instanceof DocumentTouch));
20-
2116
function useLongPress(
2217
onLongPress: (event: EventType) => void,
2318
target: BasicTarget,
@@ -30,6 +25,8 @@ function useLongPress(
3025
const timerRef = useRef<ReturnType<typeof setTimeout>>();
3126
const isTriggeredRef = useRef(false);
3227
const pervPositionRef = useRef({ x: 0, y: 0 });
28+
const mousePressed = useRef(false);
29+
const touchPressed = useRef(false);
3330
const hasMoveThreshold = !!(
3431
(moveThreshold?.x && moveThreshold.x > 0) ||
3532
(moveThreshold?.y && moveThreshold.y > 0)
@@ -60,7 +57,6 @@ function useLongPress(
6057
clientY: event.touches[0].clientY,
6158
};
6259
}
63-
6460
if (event instanceof MouseEvent) {
6561
return {
6662
clientX: event.clientX,
@@ -73,64 +69,119 @@ function useLongPress(
7369
return { clientX: 0, clientY: 0 };
7470
}
7571

76-
const onStart = (event: EventType) => {
72+
const createTimer = (event: EventType) => {
73+
timerRef.current = setTimeout(() => {
74+
onLongPressRef.current(event);
75+
isTriggeredRef.current = true;
76+
}, delay);
77+
};
78+
79+
const onTouchStart = (event: TouchEvent) => {
80+
if (touchPressed.current) return;
81+
touchPressed.current = true;
82+
7783
if (hasMoveThreshold) {
7884
const { clientX, clientY } = getClientPosition(event);
7985
pervPositionRef.current.x = clientX;
8086
pervPositionRef.current.y = clientY;
8187
}
82-
timerRef.current = setTimeout(() => {
83-
onLongPressRef.current(event);
84-
isTriggeredRef.current = true;
85-
}, delay);
88+
createTimer(event);
8689
};
8790

88-
const onMove = (event: TouchEvent) => {
91+
const onMouseDown = (event: MouseEvent) => {
92+
if ((event as any)?.sourceCapabilities?.firesTouchEvents) return;
93+
94+
mousePressed.current = true;
95+
96+
if (hasMoveThreshold) {
97+
pervPositionRef.current.x = event.clientX;
98+
pervPositionRef.current.y = event.clientY;
99+
}
100+
createTimer(event);
101+
};
102+
103+
const onMove = (event: EventType) => {
89104
if (timerRef.current && overThreshold(event)) {
90105
clearTimeout(timerRef.current);
91106
timerRef.current = undefined;
92107
}
93108
};
94109

95-
const onEnd = (event: EventType, shouldTriggerClick: boolean = false) => {
110+
const onTouchEnd = (event: TouchEvent) => {
111+
if (!touchPressed.current) return;
112+
touchPressed.current = false;
113+
96114
if (timerRef.current) {
97115
clearTimeout(timerRef.current);
116+
timerRef.current = undefined;
98117
}
118+
99119
if (isTriggeredRef.current) {
100120
onLongPressEndRef.current?.(event);
121+
} else if (onClickRef.current) {
122+
onClickRef.current(event);
123+
}
124+
isTriggeredRef.current = false;
125+
};
126+
127+
const onMouseUp = (event: MouseEvent) => {
128+
if ((event as any)?.sourceCapabilities?.firesTouchEvents) return;
129+
if (!mousePressed.current) return;
130+
mousePressed.current = false;
131+
132+
if (timerRef.current) {
133+
clearTimeout(timerRef.current);
134+
timerRef.current = undefined;
101135
}
102-
if (shouldTriggerClick && !isTriggeredRef.current && onClickRef.current) {
136+
137+
if (isTriggeredRef.current) {
138+
onLongPressEndRef.current?.(event);
139+
} else if (onClickRef.current) {
103140
onClickRef.current(event);
104141
}
105142
isTriggeredRef.current = false;
106143
};
107144

108-
const onEndWithClick = (event: EventType) => onEnd(event, true);
109-
110-
if (!touchSupported) {
111-
targetElement.addEventListener('mousedown', onStart);
112-
targetElement.addEventListener('mouseup', onEndWithClick);
113-
targetElement.addEventListener('mouseleave', onEnd);
114-
if (hasMoveThreshold) targetElement.addEventListener('mousemove', onMove);
115-
} else {
116-
targetElement.addEventListener('touchstart', onStart);
117-
targetElement.addEventListener('touchend', onEndWithClick);
118-
if (hasMoveThreshold) targetElement.addEventListener('touchmove', onMove);
145+
const onMouseLeave = (event: MouseEvent) => {
146+
if (!mousePressed.current) return;
147+
mousePressed.current = false;
148+
149+
if (timerRef.current) {
150+
clearTimeout(timerRef.current);
151+
timerRef.current = undefined;
152+
}
153+
if (isTriggeredRef.current) {
154+
onLongPressEndRef.current?.(event);
155+
isTriggeredRef.current = false;
156+
}
157+
};
158+
159+
targetElement.addEventListener('mousedown', onMouseDown);
160+
targetElement.addEventListener('mouseup', onMouseUp);
161+
targetElement.addEventListener('mouseleave', onMouseLeave);
162+
targetElement.addEventListener('touchstart', onTouchStart);
163+
targetElement.addEventListener('touchend', onTouchEnd);
164+
165+
if (hasMoveThreshold) {
166+
targetElement.addEventListener('mousemove', onMove);
167+
targetElement.addEventListener('touchmove', onMove);
119168
}
169+
120170
return () => {
121171
if (timerRef.current) {
122172
clearTimeout(timerRef.current);
123173
isTriggeredRef.current = false;
124174
}
125-
if (!touchSupported) {
126-
targetElement.removeEventListener('mousedown', onStart);
127-
targetElement.removeEventListener('mouseup', onEndWithClick);
128-
targetElement.removeEventListener('mouseleave', onEnd);
129-
if (hasMoveThreshold) targetElement.removeEventListener('mousemove', onMove);
130-
} else {
131-
targetElement.removeEventListener('touchstart', onStart);
132-
targetElement.removeEventListener('touchend', onEndWithClick);
133-
if (hasMoveThreshold) targetElement.removeEventListener('touchmove', onMove);
175+
176+
targetElement.removeEventListener('mousedown', onMouseDown);
177+
targetElement.removeEventListener('mouseup', onMouseUp);
178+
targetElement.removeEventListener('mouseleave', onMouseLeave);
179+
targetElement.removeEventListener('touchstart', onTouchStart);
180+
targetElement.removeEventListener('touchend', onTouchEnd);
181+
182+
if (hasMoveThreshold) {
183+
targetElement.removeEventListener('mousemove', onMove);
184+
targetElement.removeEventListener('touchmove', onMove);
134185
}
135186
};
136187
},

0 commit comments

Comments
 (0)