From 531187b5a4be25a1070e457d84506e8e3cfe7b10 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Sat, 17 Jan 2026 20:36:46 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=A6=E6=83=85=E9=9B=86=E6=95=B0=E5=8D=A1?= =?UTF-8?q?=E7=89=87=E5=8F=AF=E6=8B=96=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DetailPanel.tsx | 73 +++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index ff06bb5..1a4cbfd 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -90,6 +90,13 @@ const DetailPanel: React.FC = ({ const [selectedSeason, setSelectedSeason] = useState(1); const [seasonsLoaded, setSeasonsLoaded] = useState(false); + // 拖动滚动状态 + const [isDragging, setIsDragging] = useState(false); + const [isMouseDown, setIsMouseDown] = useState(false); + const [startX, setStartX] = useState(0); + const [scrollLeft, setScrollLeft] = useState(0); + const episodesScrollRef = React.useRef(null); + // 确保组件在客户端挂载后才渲染 Portal useEffect(() => { setMounted(true); @@ -495,6 +502,54 @@ const DetailPanel: React.FC = ({ } }; + // 拖动滚动处理函数 + const handleMouseDown = (e: React.MouseEvent) => { + if (!episodesScrollRef.current) return; + setIsMouseDown(true); + setStartX(e.pageX - episodesScrollRef.current.offsetLeft); + setScrollLeft(episodesScrollRef.current.scrollLeft); + }; + + const handleMouseMove = (e: React.MouseEvent) => { + if (!isMouseDown || !episodesScrollRef.current) return; + + const x = e.pageX - episodesScrollRef.current.offsetLeft; + const distance = Math.abs(x - startX); + + // 只有移动超过5px才进入拖动模式 + if (distance > 5 && !isDragging) { + setIsDragging(true); + episodesScrollRef.current.style.cursor = 'grabbing'; + episodesScrollRef.current.style.userSelect = 'none'; + } + + if (isDragging) { + e.preventDefault(); + const walk = (x - startX) * 2; // 滚动速度倍数 + episodesScrollRef.current.scrollLeft = scrollLeft - walk; + } + }; + + const handleMouseUp = () => { + setIsMouseDown(false); + setIsDragging(false); + if (episodesScrollRef.current) { + episodesScrollRef.current.style.cursor = 'grab'; + episodesScrollRef.current.style.userSelect = 'auto'; + } + }; + + const handleMouseLeave = () => { + if (isMouseDown || isDragging) { + setIsMouseDown(false); + setIsDragging(false); + if (episodesScrollRef.current) { + episodesScrollRef.current.style.cursor = 'grab'; + episodesScrollRef.current.style.userSelect = 'auto'; + } + } + }; + if (!isVisible || !mounted) return null; const content = ( @@ -552,7 +607,7 @@ const DetailPanel: React.FC = ({
{detailData.poster && (
- {detailData.title} + {detailData.title}
)}
@@ -737,6 +792,7 @@ const DetailPanel: React.FC = ({ alt={season.name} fill className="object-cover" + draggable={false} />
)} @@ -760,7 +816,18 @@ const DetailPanel: React.FC = ({

{seasonData.seasons.find((s: any) => s.season_number === selectedSeason)?.name || `第${selectedSeason}季`}

-
+
{seasonData.episodes.map((episode: Episode) => { const isExpanded = expandedEpisodes.has(episode.id); @@ -768,6 +835,7 @@ const DetailPanel: React.FC = ({
{episode.still_path && (
@@ -776,6 +844,7 @@ const DetailPanel: React.FC = ({ alt={episode.name} fill className="object-cover" + draggable={false} />
)}