mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-05-22 22:57:35 +08:00
fix: video card touch
This commit is contained in:
@@ -212,19 +212,29 @@ const VideoCard = forwardRef<VideoCardHandle, VideoCardProps>(function VideoCard
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
|
console.log('🎬 VideoCard handleClick - 被调用', {
|
||||||
|
from,
|
||||||
|
actualSource,
|
||||||
|
actualId,
|
||||||
|
actualTitle,
|
||||||
|
isAggregate
|
||||||
|
});
|
||||||
|
|
||||||
if (from === 'douban' || (isAggregate && !actualSource && !actualId)) {
|
if (from === 'douban' || (isAggregate && !actualSource && !actualId)) {
|
||||||
router.push(
|
const url = `/play?title=${encodeURIComponent(actualTitle.trim())}${actualYear ? `&year=${actualYear}` : ''
|
||||||
`/play?title=${encodeURIComponent(actualTitle.trim())}${actualYear ? `&year=${actualYear}` : ''
|
}${actualSearchType ? `&stype=${actualSearchType}` : ''}${isAggregate ? '&prefer=true' : ''}${actualQuery ? `&stitle=${encodeURIComponent(actualQuery.trim())}` : ''}`;
|
||||||
}${actualSearchType ? `&stype=${actualSearchType}` : ''}${isAggregate ? '&prefer=true' : ''}${actualQuery ? `&stitle=${encodeURIComponent(actualQuery.trim())}` : ''}`
|
console.log('🎬 VideoCard handleClick - 导航到豆瓣/聚合:', url);
|
||||||
);
|
router.push(url);
|
||||||
} else if (actualSource && actualId) {
|
} else if (actualSource && actualId) {
|
||||||
router.push(
|
const url = `/play?source=${actualSource}&id=${actualId}&title=${encodeURIComponent(
|
||||||
`/play?source=${actualSource}&id=${actualId}&title=${encodeURIComponent(
|
actualTitle
|
||||||
actualTitle
|
)}${actualYear ? `&year=${actualYear}` : ''}${isAggregate ? '&prefer=true' : ''
|
||||||
)}${actualYear ? `&year=${actualYear}` : ''}${isAggregate ? '&prefer=true' : ''
|
|
||||||
}${actualQuery ? `&stitle=${encodeURIComponent(actualQuery.trim())}` : ''
|
}${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,
|
from,
|
||||||
@@ -538,6 +548,7 @@ const VideoCard = forwardRef<VideoCardHandle, VideoCardProps>(function VideoCard
|
|||||||
{/* 播放按钮 */}
|
{/* 播放按钮 */}
|
||||||
{config.showPlayButton && (
|
{config.showPlayButton && (
|
||||||
<div
|
<div
|
||||||
|
data-button="true"
|
||||||
className='absolute inset-0 flex items-center justify-center opacity-0 transition-all duration-300 ease-in-out delay-75 group-hover:opacity-100 group-hover:scale-100'
|
className='absolute inset-0 flex items-center justify-center opacity-0 transition-all duration-300 ease-in-out delay-75 group-hover:opacity-100 group-hover:scale-100'
|
||||||
style={{
|
style={{
|
||||||
WebkitUserSelect: 'none',
|
WebkitUserSelect: 'none',
|
||||||
@@ -569,6 +580,7 @@ const VideoCard = forwardRef<VideoCardHandle, VideoCardProps>(function VideoCard
|
|||||||
{/* 操作按钮 */}
|
{/* 操作按钮 */}
|
||||||
{(config.showHeart || config.showCheckCircle) && (
|
{(config.showHeart || config.showCheckCircle) && (
|
||||||
<div
|
<div
|
||||||
|
data-button="true"
|
||||||
className='absolute bottom-3 right-3 flex gap-3 opacity-0 translate-y-2 transition-all duration-300 ease-in-out group-hover:opacity-100 group-hover:translate-y-0'
|
className='absolute bottom-3 right-3 flex gap-3 opacity-0 translate-y-2 transition-all duration-300 ease-in-out group-hover:opacity-100 group-hover:translate-y-0'
|
||||||
style={{
|
style={{
|
||||||
WebkitUserSelect: 'none',
|
WebkitUserSelect: 'none',
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export const useLongPress = ({
|
|||||||
const pressTimer = useRef<NodeJS.Timeout | null>(null);
|
const pressTimer = useRef<NodeJS.Timeout | null>(null);
|
||||||
const startPosition = useRef<TouchPosition | null>(null);
|
const startPosition = useRef<TouchPosition | null>(null);
|
||||||
const isActive = useRef(false); // 防止重复触发
|
const isActive = useRef(false); // 防止重复触发
|
||||||
|
const wasButton = useRef(false); // 记录触摸开始时是否是按钮
|
||||||
|
|
||||||
const clearTimer = useCallback(() => {
|
const clearTimer = useCallback(() => {
|
||||||
if (pressTimer.current) {
|
if (pressTimer.current) {
|
||||||
@@ -31,19 +32,29 @@ export const useLongPress = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleStart = useCallback(
|
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;
|
isActive.current = true;
|
||||||
isLongPress.current = false;
|
isLongPress.current = false;
|
||||||
startPosition.current = { x: clientX, y: clientY };
|
startPosition.current = { x: clientX, y: clientY };
|
||||||
|
|
||||||
|
// 记录触摸开始时是否是按钮
|
||||||
|
wasButton.current = isButton;
|
||||||
|
console.log('🟢 handleStart - 设置状态完成,wasButton:', wasButton.current);
|
||||||
|
|
||||||
pressTimer.current = setTimeout(() => {
|
pressTimer.current = setTimeout(() => {
|
||||||
// 再次检查是否仍然活跃
|
// 再次检查是否仍然活跃
|
||||||
if (!isActive.current) return;
|
if (!isActive.current) return;
|
||||||
|
|
||||||
isLongPress.current = true;
|
isLongPress.current = true;
|
||||||
|
console.log('🔵 长按触发');
|
||||||
|
|
||||||
// 添加触觉反馈(如果支持)
|
// 添加触觉反馈(如果支持)
|
||||||
if (navigator.vibrate) {
|
if (navigator.vibrate) {
|
||||||
@@ -68,6 +79,7 @@ export const useLongPress = ({
|
|||||||
|
|
||||||
// 如果移动距离超过阈值,取消长按
|
// 如果移动距离超过阈值,取消长按
|
||||||
if (distance > moveThreshold) {
|
if (distance > moveThreshold) {
|
||||||
|
console.log('🔴 handleMove - 移动距离超过阈值,取消手势, distance:', distance, 'threshold:', moveThreshold);
|
||||||
clearTimer();
|
clearTimer();
|
||||||
isActive.current = false;
|
isActive.current = false;
|
||||||
}
|
}
|
||||||
@@ -76,25 +88,57 @@ export const useLongPress = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleEnd = useCallback(() => {
|
const handleEnd = useCallback(() => {
|
||||||
|
console.log('🟡 handleEnd - isLongPress:', isLongPress.current, 'wasButton:', wasButton.current, 'isActive:', isActive.current, 'hasOnClick:', !!onClick);
|
||||||
|
|
||||||
clearTimer();
|
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();
|
onClick();
|
||||||
|
} else {
|
||||||
|
console.log('❌ 不触发点击事件 - 原因:', {
|
||||||
|
isLongPress: isLongPress.current,
|
||||||
|
wasButton: wasButton.current,
|
||||||
|
hasOnClick: !!onClick,
|
||||||
|
isActive: isActive.current
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置所有状态
|
// 重置所有状态
|
||||||
isLongPress.current = false;
|
isLongPress.current = false;
|
||||||
startPosition.current = null;
|
startPosition.current = null;
|
||||||
isActive.current = false;
|
isActive.current = false;
|
||||||
|
wasButton.current = false;
|
||||||
}, [clearTimer, onClick]);
|
}, [clearTimer, onClick]);
|
||||||
|
|
||||||
// 触摸事件处理器
|
// 触摸事件处理器
|
||||||
const onTouchStart = useCallback(
|
const onTouchStart = useCallback(
|
||||||
(e: React.TouchEvent) => {
|
(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];
|
const touch = e.touches[0];
|
||||||
handleStart(touch.clientX, touch.clientY);
|
handleStart(touch.clientX, touch.clientY, !!isButton);
|
||||||
},
|
},
|
||||||
[handleStart]
|
[handleStart]
|
||||||
);
|
);
|
||||||
@@ -102,6 +146,7 @@ export const useLongPress = ({
|
|||||||
const onTouchMove = useCallback(
|
const onTouchMove = useCallback(
|
||||||
(e: React.TouchEvent) => {
|
(e: React.TouchEvent) => {
|
||||||
const touch = e.touches[0];
|
const touch = e.touches[0];
|
||||||
|
console.log('📱 onTouchMove - 移动');
|
||||||
handleMove(touch.clientX, touch.clientY);
|
handleMove(touch.clientX, touch.clientY);
|
||||||
},
|
},
|
||||||
[handleMove]
|
[handleMove]
|
||||||
@@ -109,6 +154,7 @@ export const useLongPress = ({
|
|||||||
|
|
||||||
const onTouchEnd = useCallback(
|
const onTouchEnd = useCallback(
|
||||||
(e: React.TouchEvent) => {
|
(e: React.TouchEvent) => {
|
||||||
|
console.log('📱 onTouchEnd - 结束');
|
||||||
// 始终阻止默认行为,避免任何系统长按菜单
|
// 始终阻止默认行为,避免任何系统长按菜单
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -117,37 +163,11 @@ export const useLongPress = ({
|
|||||||
[handleEnd]
|
[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 {
|
return {
|
||||||
onTouchStart,
|
onTouchStart,
|
||||||
onTouchMove,
|
onTouchMove,
|
||||||
onTouchEnd,
|
onTouchEnd,
|
||||||
onMouseDown,
|
|
||||||
onMouseMove,
|
|
||||||
onMouseUp,
|
|
||||||
onMouseLeave,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user