audio标签不支持自动切歌,需用JavaScript监听ended事件实现:更换src后调用load()和play(),注意iOS首次播放需用户手势触发,后续切歌要检查readyState并处理play()拒绝。

audio 标签不支持自动切歌,必须用 JavaScript 控制
HTML 的 <audio></audio> 标签本身只负责播放单个音频,autoplay 属性只能自动播第一首,播完就停——它没有“下一首”概念。所谓“自动切歌”,本质是监听当前音频结束事件,再用 JS 换源、重载、播放下一条。
监听 ended 事件是关键入口
这是最可靠、浏览器兼容性最好的触发点。注意不是 timeupdate 或轮询 currentTime,那些既不准又浪费资源。
-
ended在音频自然播放完毕(非用户暂停/中断)时触发,时机精准 - 需确保音频已加载完成(
loadeddata或canplay后再绑定),否则可能漏掉第一次ended - 移动端 iOS Safari 默认禁止自动播放,即使加了
autoplay和muted,首次播放仍需用户手势触发(比如点击按钮),之后的自动切歌才可继续
切换音频源要调用 load() 再 play()
只改 src 属性不会自动重新加载或播放;必须显式调用 load() 重置媒体元素状态,再调用 play() 启动播放。否则可能出现静音、卡住或报错 DOMException: The element has no supported sources。
const audio = document.querySelector('audio');
const playlist = ['song1.mp3', 'song2.mp3', 'song3.mp3'];
let index = 0;
function playNext() {
if (index >= playlist.length) return;
audio.src = playlist[index++];
audio.load(); // 必须
audio.play().catch(e => console.warn('Auto-play prevented:', e));
}
audio.addEventListener('ended', playNext);
循环播放要注意 index 越界和静音策略
如果要做无限循环,index %= playlist.length 是最简方式;但更关键的是:iOS/Safari 对无用户交互后的自动 play() 极其敏感,哪怕上一首是用户点的,切到第二首也可能被拦截。稳妥做法是:
立即学习“前端免费学习笔记(深入)”;
- 首次播放用按钮触发,同时保存用户手势上下文
- 后续切歌前检查
audio.readyState >= 2(表示已有足够数据可播放) - 对
play()的 Promise 拒绝做降级处理:比如静音后重试,或 fallback 到显示“点击继续播放”提示 - 避免在
ended中连续多次play(),会触发浏览器防滥用机制
自动切歌真正难的不是逻辑,而是跨端行为不一致——尤其是静音、加载延迟、权限策略这些看不见的环节,往往调试半天才发现是 iOS 某个版本把 play() 拦在了第三首。



















