loop属性需音频真正播放后才生效,常见“不循环”实为播放未启动:src错误、缺少用户交互、preload过早调用play()、mp3损坏或ios限制;正确写法为布尔属性loop或loop="",动态设src后须等loadeddata再设loop=true;ios safari要求用户手势触发首次播放且需完整解码才循环;更可靠方案是监听ended事件手动重置currenttime并play()。

loop 属性能实现循环播放,但只在音频真正开始播放后才起作用;多数“加了不循环”的问题,根源是音频压根没播起来,而不是 loop 写错了。
为什么写了 loop 却只播一次?
不是 loop 失效,而是播放流程卡在了前面环节:
- 音频
src路径错误或返回 404,network面板能看到请求失败,此时play()被静默拒绝 - 页面未发生用户交互(如点击、触摸),Chrome / Safari 会阻止自动播放,
autoplay+loop组合直接被策略拦截 -
preload="none"且未监听loadeddata或canplay就调用play(),浏览器还没拿到元数据,无法进入播放状态 - MP3 文件头损坏或编码异常,导致末尾无法被识别为“正常结束”,
ended不触发,原生 loop 也就没机会启动
loop 属性的正确写法和常见误写
loop 是布尔属性,只看“是否存在”,不认值:
- ✅ 正确:
<audio loop src="sound.mp3"></audio>或<audio loop="" src="sound.mp3"></audio> - ❌ 无效:
loop="true"、loop="loop"、loop="false"—— 浏览器一律当没写 - ❌ JS 中错写:
audio.loop = "true";必须是audio.loop = true(布尔值) - ⚠️ 动态设置
src后,需等loadeddata事件再设loop = true,否则部分浏览器忽略
移动端 iOS Safari 的 loop 为什么总失效?
iOS Safari 对 loop 的限制最严格,它不是 bug,而是设计行为:
- 即使写了
loop,若首次play()不是由用户手势(click/touchstart)触发,整个循环逻辑会被静默禁用 - 它只在“音频完整解码并自然播放到末尾”时才触发循环;网络中断、缓冲不足、快速切页都会导致
ended不触发 -
autoplay在 iOS 上基本不可用,哪怕加了muted也不行 —— 必须显式按钮触发第一次播放 - 服务端响应头若缺少
Accept-Ranges: bytes,Safari 无法准确 seek 到结尾,循环点识别失败
比 loop 更可靠:用 ended 事件手动控制循环
绕过原生 loop 的不确定性,监听 ended 并重置时间,是跨平台兜底方案:
- 监听
ended前先检查readyState:if (audio.readyState >= audio.HAVE_FUTURE_DATA),避免currentTime = 0失败静默忽略 - 移动端必须确保首次
play()已由用户触发,后续play()才不会被NotAllowedError拦截 - 不要在
ended回调里直接play(),建议先load()再play(),尤其对动态src或跨域资源 - 若要循环指定次数(比如 3 次),只能靠 JS 计数:
let count = 0,每次ended自增,count 才重播,否则 <code>pause()
真正麻烦的从来不是怎么写循环,而是如何让“循环”这件事符合预期:什么时候该停、跳到哪一秒、是否允许用户中途打断——这些都得靠 JS 状态管理来补足,loop 只是个开关,连“开”了之后怎么转都不知道。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











