From 7192e1bf2faeee89635513f7e87f030983475223 Mon Sep 17 00:00:00 2001 From: jarvis2f <137974272+jarvis2f@users.noreply.github.com> Date: Wed, 19 Feb 2025 15:50:35 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20Enhance=20draggable=20eleme?= =?UTF-8?q?nt=20with=20multi-sensor=20support=20for=20improved=20user=20in?= =?UTF-8?q?teraction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/ui/draggable-element.tsx | 99 +++++++-------------- 1 file changed, 31 insertions(+), 68 deletions(-) diff --git a/web/src/components/ui/draggable-element.tsx b/web/src/components/ui/draggable-element.tsx index 297d192..4782c5e 100644 --- a/web/src/components/ui/draggable-element.tsx +++ b/web/src/components/ui/draggable-element.tsx @@ -1,87 +1,38 @@ -import React, { useRef, useState } from "react"; -import { DndContext, type DragEndEvent, useDraggable } from "@dnd-kit/core"; +import React, { useState } from "react"; +import { + DndContext, + type DragEndEvent, + KeyboardSensor, + MouseSensor, + TouchSensor, + useDraggable, + useSensor, + useSensors, +} from "@dnd-kit/core"; import { Portal } from "@radix-ui/react-portal"; import { cn } from "@/lib/utils"; interface DraggableElementProps { children: React.ReactNode; className?: string; - onTap?: () => void; - longPressTime?: number; // 长按触发拖拽的时间 (ms) } const DraggableContent = ({ children, className = "", style, - onTap, - longPressTime = 300, }: DraggableElementProps & { style: React.CSSProperties }) => { const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({ id: "draggable-element", }); - const touchStartTime = useRef(0); - const touchStartPos = useRef<{ x: number; y: number } | null>(null); - const longPressTimer = useRef(); - const [isLongPress, setIsLongPress] = useState(false); - const transformStyle = transform ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, } : {}; - const handleTouchStart = (e: React.TouchEvent) => { - touchStartTime.current = Date.now(); - touchStartPos.current = { - x: e.touches[0]!.clientX, - y: e.touches[0]!.clientY, - }; - - longPressTimer.current = setTimeout(() => { - setIsLongPress(true); - }, longPressTime); - }; - - const handleTouchEnd = (e: React.TouchEvent) => { - clearTimeout(longPressTimer.current); - - if (touchStartPos.current) { - const touchEndX = e.changedTouches[0]!.clientX; - const touchEndY = e.changedTouches[0]!.clientY; - const deltaX = Math.abs(touchEndX - touchStartPos.current.x); - const deltaY = Math.abs(touchEndY - touchStartPos.current.y); - const touchDuration = Date.now() - touchStartTime.current; - - // 如果移动距离小于阈值且不是长按,则视为点击 - if ( - deltaX < 5 && - deltaY < 5 && - touchDuration < longPressTime && - !isLongPress - ) { - onTap?.(); - } - } - - setIsLongPress(false); - touchStartPos.current = null; - }; - - const handleTouchMove = (e: React.TouchEvent) => { - if (touchStartPos.current) { - const deltaX = Math.abs(e.touches[0]!.clientX - touchStartPos.current.x); - const deltaY = Math.abs(e.touches[0]!.clientY - touchStartPos.current.y); - - // 如果移动距离超过阈值,取消长按计时 - if (deltaX > 5 || deltaY > 5) { - clearTimeout(longPressTimer.current); - } - } - }; - const preventContextMenu = (e: React.MouseEvent | React.TouchEvent) => { e.preventDefault(); e.stopPropagation(); @@ -90,12 +41,12 @@ const DraggableContent = ({ return (
{children}
- {isLongPress && ( + {isDragging && (
)}
@@ -129,6 +77,21 @@ const DraggableElement = (props: DraggableElementProps) => { y: window.innerHeight - 60, }); + const mouseSensor = useSensor(MouseSensor, { + activationConstraint: { + delay: 250, + tolerance: 5, + }, + }); + const touchSensor = useSensor(TouchSensor, { + activationConstraint: { + delay: 250, + tolerance: 5, + }, + }); + const keyboardSensor = useSensor(KeyboardSensor, {}); + const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor); + const handleDragEnd = (event: DragEndEvent) => { const { delta } = event; @@ -152,7 +115,7 @@ const DraggableElement = (props: DraggableElementProps) => { return ( - +