音频ended事件触发后无法暂停/播放问题求助
问题描述
首次加载曲目时,暂停按钮功能正常,可暂停音频并切换按钮图标;通过上一曲/下一曲按钮切换歌曲后,按钮仍能正常工作。但当audio.addEventListener('ended', nextTrack);事件触发自动切歌后,暂停按钮仅能切换图标和playing变量状态,无法控制音频的播放/暂停,所有音频的暂停/播放功能彻底失效。
相关代码
let audio = new Audio; let playing = false; let playpause = document.getElementById('play-pause'); let root = document.documentElement; let songname = document.getElementById('name'); let next = document.getElementById('next'); let prev = document.getElementById('previous'); let index = 0; songlist = [ {"name":"Love Again" ,"artist":"The Kid LAROI", "path":"resources/music/love-again.mp3", }, { "name":"Always Do", "artist":"The Kid LAROI", "path":"resources/music/always-do.mp3", }, { "name":"Bye Bye", "artist":"Juice WRLD", "path":"resources/music/bye-bye.mp3", }, { "name":"Understand", "artist":"BoyWithUke", "path":"resources/music/understand.mp3", } ] function progress_animation(){ var currentTime = audio.currentTime; var duration = audio.duration; $('#progbar').stop(true, true).animate({ 'width': (currentTime + .25) / duration * 100 + '%' }, 250, 'linear'); window.requestAnimationFrame(progress_animation); }; function load(index){ songname.textContent = `${songlist[index].artist} - ${songlist[index].name}`; audio.src = songlist[index].path; audio.load() }; audio.addEventListener('ended', nextTrack); $('#play-pause').click(function (){ if (!playing) { Play() playing = true } else { Pause() playing = false } }); function nextTrack(){ if (index < songlist.length - 1) { index++; } else { index = 0; } load(index); }; function prevTrack(){ if (index > 0) { index--; } else { index = songlist.length - 1; } load(index); }; function Play() { audio.play(); playing = true; playpause.innerHTML = '<i class="fa-solid fa-pause"></i>'; }; function Pause() { audio.pause() playing = false; playpause.innerHTML = '<i class="fa-solid fa-play"></i>'; };
问题原因与修复方案
核心问题
- 状态不同步:音频自然结束时,未更新
playing变量状态,导致切歌后playing仍为true,但新加载的音频处于未播放状态,点击按钮时逻辑完全混乱。 - 切歌后未自动续播:原逻辑中歌曲结束后应该自动播放下一首,但
nextTrack仅加载新音频,未触发播放操作。 - 进度动画潜在错误:音频未加载完成时
audio.duration为NaN,会导致动画代码报错,影响后续功能。
修复后的代码
let audio = new Audio; let playing = false; let playpause = document.getElementById('play-pause'); let root = document.documentElement; let songname = document.getElementById('name'); let next = document.getElementById('next'); let prev = document.getElementById('previous'); let index = 0; songlist = [ {"name":"Love Again" ,"artist":"The Kid LAROI", "path":"resources/music/love-again.mp3", }, { "name":"Always Do", "artist":"The Kid LAROI", "path":"resources/music/always-do.mp3", }, { "name":"Bye Bye", "artist":"Juice WRLD", "path":"resources/music/bye-bye.mp3", }, { "name":"Understand", "artist":"BoyWithUke", "path":"resources/music/understand.mp3", } ] function progress_animation(){ var currentTime = audio.currentTime; var duration = audio.duration; // 避免音频未加载完成时的NaN错误 if (isNaN(duration)) { window.requestAnimationFrame(progress_animation); return; } $('#progbar').stop(true, true).animate({ 'width': (currentTime + .25) / duration * 100 + '%' }, 250, 'linear'); window.requestAnimationFrame(progress_animation); }; function load(index){ songname.textContent = `${songlist[index].artist} - ${songlist[index].name}`; audio.src = songlist[index].path; audio.load(); // 如果之前处于播放状态,音频加载完成后自动播放 if (playing) { // 监听音频可播放事件,确保加载完成后再播放 audio.addEventListener('canplay', function playNewTrack() { audio.play(); // 移除一次性监听,避免重复触发 audio.removeEventListener('canplay', playNewTrack); }, { once: true }); } }; // 修改ended事件处理,先更新状态再切歌 audio.addEventListener('ended', function() { Pause(); // 先同步状态为未播放 nextTrack(); // 自动播放下一首 Play(); }); $('#play-pause').click(function (){ if (!playing) { Play() } else { Pause() } }); function nextTrack(){ if (index < songlist.length - 1) { index++; } else { index = 0; } load(index); }; function prevTrack(){ if (index > 0) { index--; } else { index = songlist.length - 1; } load(index); }; function Play() { // 确保音频加载完成再播放,捕获播放失败错误 if (audio.src) { audio.play().catch(err => console.error('播放失败:', err)); } playing = true; playpause.innerHTML = '<i class="fa-solid fa-pause"></i>'; }; function Pause() { audio.pause(); playing = false; playpause.innerHTML = '<i class="fa-solid fa-play"></i>'; }; // 初始化加载第一首歌 load(index);
关键修改点
- ended事件处理优化:音频结束时先调用
Pause()同步状态,再切歌并自动播放下一首,确保状态与音频实际播放情况一致。 - load函数增强:添加音频
canplay事件监听,确保新音频加载完成后再播放,避免因未加载完成导致的播放失败;同时根据当前playing状态决定是否自动播放。 - 进度动画容错:增加
isNaN(duration)判断,避免音频未加载时的代码报错。 - Play函数容错:添加播放错误捕获,同时判断音频src是否存在,避免无意义的播放调用。
内容的提问来源于stack exchange,提问作者doare
相关产品推荐
相关产品推荐

