From 4bda206888ca668b2c4854d3985836c8d636ae1f Mon Sep 17 00:00:00 2001 From: shinya Date: Fri, 22 Aug 2025 00:30:44 +0800 Subject: [PATCH] fix: video card touch --- src/components/VideoCard.tsx | 32 +++++++++----- src/hooks/useLongPress.ts | 82 ++++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 41 deletions(-) diff --git a/src/components/VideoCard.tsx b/src/components/VideoCard.tsx index d8423f4..6a9d808 100644 --- a/src/components/VideoCard.tsx +++ b/src/components/VideoCard.tsx @@ -212,19 +212,29 @@ const VideoCard = forwardRef(function VideoCard ); const handleClick = useCallback(() => { + console.log('🎬 VideoCard handleClick - 被调用', { + from, + actualSource, + actualId, + actualTitle, + isAggregate + }); + if (from === 'douban' || (isAggregate && !actualSource && !actualId)) { - router.push( - `/play?title=${encodeURIComponent(actualTitle.trim())}${actualYear ? `&year=${actualYear}` : '' - }${actualSearchType ? `&stype=${actualSearchType}` : ''}${isAggregate ? '&prefer=true' : ''}${actualQuery ? `&stitle=${encodeURIComponent(actualQuery.trim())}` : ''}` - ); + const url = `/play?title=${encodeURIComponent(actualTitle.trim())}${actualYear ? `&year=${actualYear}` : '' + }${actualSearchType ? `&stype=${actualSearchType}` : ''}${isAggregate ? '&prefer=true' : ''}${actualQuery ? `&stitle=${encodeURIComponent(actualQuery.trim())}` : ''}`; + console.log('🎬 VideoCard handleClick - 导航到豆瓣/聚合:', url); + router.push(url); } else if (actualSource && actualId) { - router.push( - `/play?source=${actualSource}&id=${actualId}&title=${encodeURIComponent( - actualTitle - )}${actualYear ? `&year=${actualYear}` : ''}${isAggregate ? '&prefer=true' : '' + const url = `/play?source=${actualSource}&id=${actualId}&title=${encodeURIComponent( + actualTitle + )}${actualYear ? `&year=${actualYear}` : ''}${isAggregate ? '&prefer=true' : '' }${actualQuery ? `&stitle=${encodeURIComponent(actualQuery.trim())}` : '' - }${actualSearchType ? `&stype=${actualSearchType}` : ''}` - ); + }${actualSearchType ? `&stype=${actualSearchType}` : ''}`; + console.log('🎬 VideoCard handleClick - 导航到播放页:', url); + router.push(url); + } else { + console.log('🔴 VideoCard handleClick - 无法导航,缺少必要参数'); } }, [ from, @@ -538,6 +548,7 @@ const VideoCard = forwardRef(function VideoCard {/* 播放按钮 */} {config.showPlayButton && (
(function VideoCard {/* 操作按钮 */} {(config.showHeart || config.showCheckCircle) && (
(null); const startPosition = useRef(null); const isActive = useRef(false); // 防止重复触发 + const wasButton = useRef(false); // 记录触摸开始时是否是按钮 const clearTimer = useCallback(() => { if (pressTimer.current) { @@ -31,19 +32,29 @@ export const useLongPress = ({ }, []); const handleStart = useCallback( - (clientX: number, clientY: number) => { + (clientX: number, clientY: number, isButton: boolean = false) => { + console.log('🟡 handleStart - isButton:', isButton, 'isActive:', isActive.current); + // 如果已经有活跃的手势,忽略新的开始 - if (isActive.current) return; + if (isActive.current) { + console.log('🔴 handleStart - 已有活跃手势,忽略'); + return; + } isActive.current = true; isLongPress.current = false; startPosition.current = { x: clientX, y: clientY }; + // 记录触摸开始时是否是按钮 + wasButton.current = isButton; + console.log('🟢 handleStart - 设置状态完成,wasButton:', wasButton.current); + pressTimer.current = setTimeout(() => { // 再次检查是否仍然活跃 if (!isActive.current) return; isLongPress.current = true; + console.log('🔵 长按触发'); // 添加触觉反馈(如果支持) if (navigator.vibrate) { @@ -68,6 +79,7 @@ export const useLongPress = ({ // 如果移动距离超过阈值,取消长按 if (distance > moveThreshold) { + console.log('🔴 handleMove - 移动距离超过阈值,取消手势, distance:', distance, 'threshold:', moveThreshold); clearTimer(); isActive.current = false; } @@ -76,25 +88,57 @@ export const useLongPress = ({ ); const handleEnd = useCallback(() => { + console.log('🟡 handleEnd - isLongPress:', isLongPress.current, 'wasButton:', wasButton.current, 'isActive:', isActive.current, 'hasOnClick:', !!onClick); + clearTimer(); - // 如果不是长按且手势仍然活跃,则触发点击事件 - if (!isLongPress.current && onClick && isActive.current) { + // 根据情况决定是否触发点击事件: + // 1. 如果是长按,不触发点击 + // 2. 如果不是长按且触摸开始时是按钮,不触发点击 + // 3. 否则触发点击 + const shouldClick = !isLongPress.current && !wasButton.current && onClick && isActive.current; + console.log('🟢 handleEnd - shouldClick:', shouldClick); + + if (shouldClick) { + console.log('🚀 触发点击事件'); onClick(); + } else { + console.log('❌ 不触发点击事件 - 原因:', { + isLongPress: isLongPress.current, + wasButton: wasButton.current, + hasOnClick: !!onClick, + isActive: isActive.current + }); } // 重置所有状态 isLongPress.current = false; startPosition.current = null; isActive.current = false; + wasButton.current = false; }, [clearTimer, onClick]); // 触摸事件处理器 const onTouchStart = useCallback( (e: React.TouchEvent) => { + console.log('📱 onTouchStart - 开始'); + + // 检查是否触摸的是按钮或其他交互元素 + const target = e.target as HTMLElement; + const buttonElement = target.closest('[data-button]'); + + // 更精确的按钮检测:只有当触摸目标直接是按钮元素或其直接子元素时才认为是按钮 + const isDirectButton = target.hasAttribute('data-button'); + const isButton = !!buttonElement && isDirectButton; + + console.log('📱 onTouchStart - target:', target.tagName, target.className); + console.log('📱 onTouchStart - buttonElement:', buttonElement); + console.log('📱 onTouchStart - isDirectButton:', isDirectButton); + console.log('📱 onTouchStart - isButton:', isButton); + // 阻止默认的长按行为,但不阻止触摸开始事件 const touch = e.touches[0]; - handleStart(touch.clientX, touch.clientY); + handleStart(touch.clientX, touch.clientY, !!isButton); }, [handleStart] ); @@ -102,6 +146,7 @@ export const useLongPress = ({ const onTouchMove = useCallback( (e: React.TouchEvent) => { const touch = e.touches[0]; + console.log('📱 onTouchMove - 移动'); handleMove(touch.clientX, touch.clientY); }, [handleMove] @@ -109,6 +154,7 @@ export const useLongPress = ({ const onTouchEnd = useCallback( (e: React.TouchEvent) => { + console.log('📱 onTouchEnd - 结束'); // 始终阻止默认行为,避免任何系统长按菜单 e.preventDefault(); e.stopPropagation(); @@ -117,37 +163,11 @@ export const useLongPress = ({ [handleEnd] ); - // 鼠标事件处理器(用于桌面端测试) - const onMouseDown = useCallback( - (e: React.MouseEvent) => { - handleStart(e.clientX, e.clientY); - }, - [handleStart] - ); - const onMouseMove = useCallback( - (e: React.MouseEvent) => { - handleMove(e.clientX, e.clientY); - }, - [handleMove] - ); - - const onMouseUp = useCallback(() => { - handleEnd(); - }, [handleEnd]); - - const onMouseLeave = useCallback(() => { - clearTimer(); - isActive.current = false; - }, [clearTimer]); return { onTouchStart, onTouchMove, onTouchEnd, - onMouseDown, - onMouseMove, - onMouseUp, - onMouseLeave, }; };