Skip to content

Commit af73306

Browse files
committed
fix: 修复选集点击偏移问题,优化事件处理和布局
1 parent f0bbcf0 commit af73306

File tree

3 files changed

+159
-5
lines changed

3 files changed

+159
-5
lines changed

EPISODE_CLICK_DEEP_FIX.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# 选集点击偏移问题的深度修复
2+
3+
## 问题复现
4+
5+
用户点击第 6 集(紫色框框),但系统选择了第 7 集(绿色填充),存在点击偏移问题。
6+
7+
## 深度分析与修复
8+
9+
### 🔍 问题根因分析
10+
11+
经过多轮调试,发现问题有**多个层面**
12+
13+
#### 1. CSS Grid 布局问题
14+
15+
```css
16+
/* 问题代码 */
17+
grid-cols-[repeat(auto-fill,minmax(40px,1fr))]
18+
19+
/* 问题分析 */
20+
- minmax(40px,1fr) 中的 1fr 导致按钮宽度不固定
21+
- 在不同屏幕宽度下,按钮实际宽度变化很大
22+
- 视觉按钮位置与点击区域不匹配
23+
```
24+
25+
#### 2. 事件处理逻辑问题
26+
27+
```javascript
28+
// 问题代码
29+
const handleEpisodeChange = (episodeNumber: number) => {
30+
if (episodeNumber >= 0 && episodeNumber < totalEpisodes) {
31+
setCurrentEpisodeIndex(episodeNumber); // 错误!
32+
}
33+
};
34+
35+
// 问题分析
36+
- EpisodeSelector传递的是显示集数(1-based): 1, 2, 3, 4, 5, 6, 7...
37+
- 但直接设置为currentEpisodeIndex(0-based): 0, 1, 2, 3, 4, 5, 6...
38+
- 导致点击第6集实际设置为index=6,对应第7集
39+
```
40+
41+
#### 3. 可能的覆盖层问题
42+
43+
- SkipController 的固定定位面板可能覆盖选集区域
44+
- 已移动到左下角,但可能不彻底
45+
46+
### 🔧 完整修复方案
47+
48+
#### 修复 1: CSS 布局优化
49+
50+
```tsx
51+
// 修复前
52+
<div className='grid grid-cols-[repeat(auto-fill,minmax(40px,1fr))] auto-rows-[40px] gap-x-3 gap-y-3'>
53+
54+
// 修复后
55+
<div className='grid grid-cols-[repeat(auto-fill,48px)] justify-center gap-3'>
56+
```
57+
58+
**效果**
59+
60+
- 每个按钮固定 48px 宽度
61+
- 使用 justify-center 居中对齐
62+
- 消除弹性宽度导致的位置偏移
63+
64+
#### 修复 2: 事件处理修正
65+
66+
```tsx
67+
// 修复前
68+
const handleEpisodeChange = (episodeNumber: number) => {
69+
if (episodeNumber >= 0 && episodeNumber < totalEpisodes) {
70+
setCurrentEpisodeIndex(episodeNumber); // 直接使用显示集数作为索引
71+
}
72+
};
73+
74+
// 修复后
75+
const handleEpisodeChange = (episodeNumber: number) => {
76+
const episodeIndex = episodeNumber - 1; // 转换:显示集数 -> 数组索引
77+
if (episodeIndex >= 0 && episodeIndex < totalEpisodes) {
78+
setCurrentEpisodeIndex(episodeIndex);
79+
}
80+
};
81+
```
82+
83+
**效果**
84+
85+
- 正确处理集数显示值到数组索引的转换
86+
- 点击第 6 集 → episodeNumber=6 → episodeIndex=5 → 正确选择第 6 集
87+
88+
#### 修复 3: 增强事件控制
89+
90+
```tsx
91+
// 添加更强的事件控制
92+
onClick={(e) => {
93+
e.preventDefault();
94+
e.stopPropagation();
95+
handleEpisodeClick(episodeNumber);
96+
}}
97+
```
98+
99+
### 🎯 修复验证
100+
101+
#### 数据流验证
102+
103+
1. **用户点击第 6 集按钮**
104+
2. **EpisodeSelector.tsx**: `handleEpisodeClick(6)``onChange(6)`
105+
3. **play/page.tsx**: `handleEpisodeChange(6)``episodeIndex = 6-1 = 5`
106+
4. **状态更新**: `setCurrentEpisodeIndex(5)` → 选中第 6 集(index=5)
107+
5. **UI 更新**: `value={currentEpisodeIndex + 1} = 5+1 = 6` → 第 6 集高亮
108+
109+
#### 布局验证
110+
111+
- 固定 48px 宽度确保按钮大小一致
112+
- justify-center 确保居中对齐
113+
- gap-3 提供合适的间距
114+
115+
### 📁 修改文件
116+
117+
1. **src/components/EpisodeSelector.tsx**
118+
119+
- 修复 CSS Grid 布局:固定按钮宽度
120+
- 增强点击事件处理
121+
122+
2. **src/app/play/page.tsx**
123+
124+
- 修复 handleEpisodeChange 逻辑错误
125+
- 正确处理显示集数到索引的转换
126+
127+
3. **src/components/SkipController.tsx**
128+
- 移动固定面板位置(之前已修复)
129+
130+
### 🚀 预期效果
131+
132+
修复后的行为:
133+
134+
- ✅ 点击第 1 集 → 选择第 1 集
135+
- ✅ 点击第 6 集 → 选择第 6 集
136+
- ✅ 点击第 7 集 → 选择第 7 集
137+
- ✅ 按钮布局美观,宽度一致
138+
- ✅ 不受屏幕宽度影响
139+
140+
### 💡 经验总结
141+
142+
1. **UI 显示值 vs 数据索引**:要区分用户看到的值(1-based)和内部索引(0-based)
143+
2. **CSS 弹性布局**:在需要精确点击的场景下,避免使用 1fr 等弹性单位
144+
3. **多层问题**:复杂 bug 可能有多个层面的原因,需要逐层排查
145+
4. **事件处理**:添加 preventDefault 和 stopPropagation 增强控制
146+
147+
这次修复解决了根本问题,确保点击精确性和用户体验。

src/app/play/page.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,12 +737,14 @@ function PlayPageClient() {
737737
// ---------------------------------------------------------------------------
738738
// 处理集数切换
739739
const handleEpisodeChange = (episodeNumber: number) => {
740-
if (episodeNumber >= 0 && episodeNumber < totalEpisodes) {
740+
// episodeNumber是显示的集数(从1开始),需要转换为索引(从0开始)
741+
const episodeIndex = episodeNumber - 1;
742+
if (episodeIndex >= 0 && episodeIndex < totalEpisodes) {
741743
// 在更换集数前保存当前播放进度
742744
if (artPlayerRef.current && artPlayerRef.current.paused) {
743745
saveCurrentPlayProgress();
744746
}
745-
setCurrentEpisodeIndex(episodeNumber);
747+
setCurrentEpisodeIndex(episodeIndex);
746748
}
747749
};
748750

src/components/EpisodeSelector.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
321321
</div>
322322

323323
{/* 集数网格 */}
324-
<div className='grid grid-cols-[repeat(auto-fill,minmax(40px,1fr))] auto-rows-[40px] gap-x-3 gap-y-3 overflow-y-auto h-full pb-4'>
324+
<div className='grid grid-cols-[repeat(auto-fill,48px)] justify-center gap-3 overflow-y-auto h-full pb-4'>
325325
{(() => {
326326
const len = currentEnd - currentStart + 1;
327327
const episodes = Array.from({ length: len }, (_, i) =>
@@ -333,13 +333,18 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
333333
return (
334334
<button
335335
key={episodeNumber}
336-
onClick={() => handleEpisodeClick(episodeNumber)}
337-
className={`h-10 flex items-center justify-center text-sm font-medium rounded-md transition-all duration-200
336+
onClick={(e) => {
337+
e.preventDefault();
338+
e.stopPropagation();
339+
handleEpisodeClick(episodeNumber);
340+
}}
341+
className={`w-12 h-10 flex items-center justify-center text-sm font-medium rounded-md transition-all duration-200 cursor-pointer
338342
${
339343
isActive
340344
? 'bg-green-500 text-white shadow-lg shadow-green-500/25 dark:bg-green-600'
341345
: 'bg-gray-200 text-gray-700 hover:bg-gray-300 hover:scale-105 dark:bg-white/10 dark:text-gray-300 dark:hover:bg-white/20'
342346
}`.trim()}
347+
type="button"
343348
>
344349
{episodeNumber}
345350
</button>

0 commit comments

Comments
 (0)