diff --git a/EPISODE_CLICK_DEEP_FIX.md b/EPISODE_CLICK_DEEP_FIX.md new file mode 100644 index 0000000..f8ba1b4 --- /dev/null +++ b/EPISODE_CLICK_DEEP_FIX.md @@ -0,0 +1,147 @@ +# 选集点击偏移问题的深度修复 + +## 问题复现 + +用户点击第 6 集(紫色框框),但系统选择了第 7 集(绿色填充),存在点击偏移问题。 + +## 深度分析与修复 + +### 🔍 问题根因分析 + +经过多轮调试,发现问题有**多个层面**: + +#### 1. CSS Grid 布局问题 + +```css +/* 问题代码 */ +grid-cols-[repeat(auto-fill,minmax(40px,1fr))] + +/* 问题分析 */ +- minmax(40px,1fr) 中的 1fr 导致按钮宽度不固定 +- 在不同屏幕宽度下,按钮实际宽度变化很大 +- 视觉按钮位置与点击区域不匹配 +``` + +#### 2. 事件处理逻辑问题 + +```javascript +// 问题代码 +const handleEpisodeChange = (episodeNumber: number) => { + if (episodeNumber >= 0 && episodeNumber < totalEpisodes) { + setCurrentEpisodeIndex(episodeNumber); // 错误! + } +}; + +// 问题分析 +- EpisodeSelector传递的是显示集数(1-based): 1, 2, 3, 4, 5, 6, 7... +- 但直接设置为currentEpisodeIndex(0-based): 0, 1, 2, 3, 4, 5, 6... +- 导致点击第6集实际设置为index=6,对应第7集 +``` + +#### 3. 可能的覆盖层问题 + +- SkipController 的固定定位面板可能覆盖选集区域 +- 已移动到左下角,但可能不彻底 + +### 🔧 完整修复方案 + +#### 修复 1: CSS 布局优化 + +```tsx +// 修复前 +
+ +// 修复后 +
+``` + +**效果**: + +- 每个按钮固定 48px 宽度 +- 使用 justify-center 居中对齐 +- 消除弹性宽度导致的位置偏移 + +#### 修复 2: 事件处理修正 + +```tsx +// 修复前 +const handleEpisodeChange = (episodeNumber: number) => { + if (episodeNumber >= 0 && episodeNumber < totalEpisodes) { + setCurrentEpisodeIndex(episodeNumber); // 直接使用显示集数作为索引 + } +}; + +// 修复后 +const handleEpisodeChange = (episodeNumber: number) => { + const episodeIndex = episodeNumber - 1; // 转换:显示集数 -> 数组索引 + if (episodeIndex >= 0 && episodeIndex < totalEpisodes) { + setCurrentEpisodeIndex(episodeIndex); + } +}; +``` + +**效果**: + +- 正确处理集数显示值到数组索引的转换 +- 点击第 6 集 → episodeNumber=6 → episodeIndex=5 → 正确选择第 6 集 + +#### 修复 3: 增强事件控制 + +```tsx +// 添加更强的事件控制 +onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + handleEpisodeClick(episodeNumber); +}} +``` + +### 🎯 修复验证 + +#### 数据流验证 + +1. **用户点击第 6 集按钮** +2. **EpisodeSelector.tsx**: `handleEpisodeClick(6)` → `onChange(6)` +3. **play/page.tsx**: `handleEpisodeChange(6)` → `episodeIndex = 6-1 = 5` +4. **状态更新**: `setCurrentEpisodeIndex(5)` → 选中第 6 集(index=5) +5. **UI 更新**: `value={currentEpisodeIndex + 1} = 5+1 = 6` → 第 6 集高亮 + +#### 布局验证 + +- 固定 48px 宽度确保按钮大小一致 +- justify-center 确保居中对齐 +- gap-3 提供合适的间距 + +### 📁 修改文件 + +1. **src/components/EpisodeSelector.tsx** + + - 修复 CSS Grid 布局:固定按钮宽度 + - 增强点击事件处理 + +2. **src/app/play/page.tsx** + + - 修复 handleEpisodeChange 逻辑错误 + - 正确处理显示集数到索引的转换 + +3. **src/components/SkipController.tsx** + - 移动固定面板位置(之前已修复) + +### 🚀 预期效果 + +修复后的行为: + +- ✅ 点击第 1 集 → 选择第 1 集 +- ✅ 点击第 6 集 → 选择第 6 集 +- ✅ 点击第 7 集 → 选择第 7 集 +- ✅ 按钮布局美观,宽度一致 +- ✅ 不受屏幕宽度影响 + +### 💡 经验总结 + +1. **UI 显示值 vs 数据索引**:要区分用户看到的值(1-based)和内部索引(0-based) +2. **CSS 弹性布局**:在需要精确点击的场景下,避免使用 1fr 等弹性单位 +3. **多层问题**:复杂 bug 可能有多个层面的原因,需要逐层排查 +4. **事件处理**:添加 preventDefault 和 stopPropagation 增强控制 + +这次修复解决了根本问题,确保点击精确性和用户体验。 diff --git a/src/app/play/page.tsx b/src/app/play/page.tsx index d0e51e4..777a3c3 100644 --- a/src/app/play/page.tsx +++ b/src/app/play/page.tsx @@ -737,12 +737,14 @@ function PlayPageClient() { // --------------------------------------------------------------------------- // 处理集数切换 const handleEpisodeChange = (episodeNumber: number) => { - if (episodeNumber >= 0 && episodeNumber < totalEpisodes) { + // episodeNumber是显示的集数(从1开始),需要转换为索引(从0开始) + const episodeIndex = episodeNumber - 1; + if (episodeIndex >= 0 && episodeIndex < totalEpisodes) { // 在更换集数前保存当前播放进度 if (artPlayerRef.current && artPlayerRef.current.paused) { saveCurrentPlayProgress(); } - setCurrentEpisodeIndex(episodeNumber); + setCurrentEpisodeIndex(episodeIndex); } }; diff --git a/src/components/EpisodeSelector.tsx b/src/components/EpisodeSelector.tsx index 2a4122a..a220b47 100644 --- a/src/components/EpisodeSelector.tsx +++ b/src/components/EpisodeSelector.tsx @@ -321,7 +321,7 @@ const EpisodeSelector: React.FC = ({
{/* 集数网格 */} -
+
{(() => { const len = currentEnd - currentStart + 1; const episodes = Array.from({ length: len }, (_, i) => @@ -333,13 +333,18 @@ const EpisodeSelector: React.FC = ({ return (