音频组件播放模式切换调试&Bug修复
概述
本节调试播放模式功能,修复单曲循环模式下切换曲目时音频意外停止的 Bug,分析问题根因并给出修复方案。
问题复现
测试步骤
- 播放音频
- 切换到单曲循环模式
- 拖拽进度条到末尾,确认单曲循环正常
- 在单曲循环模式下点击上一曲/下一曲
预期行为
- 单曲循环正常:播放到末尾后从头开始
- 点击上一曲/下一曲:切换到对应曲目并继续播放
实际行为
- 单曲循环:正常
- 切换曲目:音频停止,不再播放
根因分析
// 问题代码:switchTrack 函数中
function switchTrack(index: number) {
// ❌ 问题:无条件重置 progress 为 0
state.progress = 0
currentIndex.value = index
// 初始化新音频...
}
typescript
问题分析:
在单曲循环模式下,切换曲目时 state.progress = 0 会导致 watch 触发 seek 操作。同时由于 Howler 的 loop 属性与曲目切换逻辑冲突,导致新音频未能自动播放。
修复方案
修复 1:根据循环模式决定是否重置进度
function switchTrack(index: number) {
// 只在非单曲循环模式下重置进度
if (loopMode.value !== LoopMode.SingleLoop) {
state.progress = 0
}
currentIndex.value = index
initNewTrack(index)
}
typescript
修复 2:切换曲目后自动播放
function switchTrack(index: number) {
const wasPlaying = state.playing
currentIndex.value = index
// 初始化新曲目后,如果之前在播放,自动开始播放
initAudio(list.value[index].src, {
loop: loopMode.value === LoopMode.SingleLoop,
onload() {
state.duration = audioInstance.value!.duration()
if (wasPlaying) {
audioInstance.value!.play()
}
}
})
}
typescript
修复 3:完整的模式切换逻辑
function toggleLoopMode() {
const prevMode = loopMode.value
loopMode.value = (loopMode.value + 1) % 4
// 从单曲循环切出:关闭 Howler loop
if (prevMode === LoopMode.SingleLoop && audioInstance.value) {
audioInstance.value.loop(false)
}
// 切入单曲循环:开启 Howler loop
if (loopMode.value === LoopMode.SingleLoop && audioInstance.value) {
audioInstance.value.loop(true)
}
}
typescript
调试验证
测试用例
| 测试场景 | 操作 | 预期结果 | 修复后 |
|---|---|---|---|
| 单曲循环 | 播放到末尾 | 自动从头播放 | 通过 |
| 单曲循环 + 切下一曲 | 点击下一曲 | 切换并播放新曲目 | 通过 |
| 单曲循环 + 切上一曲 | 点击上一曲 | 切换并播放新曲目 | 通过 |
| 列表循环 + 末尾下一曲 | 最后一首点下一曲 | 回到第一首 | 通过 |
| 随机播放 | 点击下一曲 | 随机切换曲目 | 通过 |
| 顺序播放 + 末尾 | 最后一首播完 | 停止播放 | 通过 |
调试技巧
- 逐步验证:每次只改变一个变量,确认其影响
- 控制台断点:在
switchTrack和handleTrackEnd中设置断点 - 日志追踪:打印
loopMode、currentIndex、state.playing的变化 - 模拟边界:拖拽进度条到末尾触发
onend事件
小结
- 单曲循环切换曲目时的 Bug 根因:无条件重置
progress导致播放中断 - 修复要点:切换曲目时保留播放状态(
wasPlaying),新曲目加载完成后自动恢复 - 模式切换时需同步管理 Howler 的
loop属性,避免状态不一致 - 播放模式相关的 Bug 需要覆盖所有模式组合进行测试
↑