不是必须但强烈建议使用 preload="none",因默认值不一致会导致并发请求、卡顿、内存飙升及CORS预检失败;应共用一个audio实例,点击时调load()再play(),进度条需节流处理并校验duration有效性。

audio 标签必须用 preload="none" 吗?
不是必须,但强烈建议。默认 preload 值在不同浏览器中不一致(auto / metadata / none),若列表里有 10 首歌,全设为 auto 会导致页面加载时并发请求全部音频文件,卡顿、内存飙升、甚至触发 CORS 预检失败。
- 只保留一个
<audio>实例,所有歌曲共用它 - 每首歌的
<li>元素上加data-src、data-title、data-duration等属性存元信息 -
<audio preload="none">是底线:避免静默加载,确保点击才拉取 - 首次播放前必须调用
audio.load(),否则 Safari iOS 和部分安卓 WebView 会静音或报错
progress 条为什么拖不动或跳转不准?
核心原因是没处理 input[type="range"] 的 change 和 input 事件混合逻辑,且没校验 currentTime 范围。
- 监听
input事件做实时预览(用户拖动时视觉反馈),但只在change事件里真正设置audio.currentTime - 设置前务必判断
audio.duration是否有效(未加载完成时是NaN),应先监听loadedmetadata再启用进度条 - 拖动后要手动触发一次
audio.play(),否则部分浏览器(如 Chrome on Android)暂停状态下拖动不会自动恢复播放 - 别用
div+click模拟进度条——兼容性差、触摸精度低;<input type="range">是唯一稳妥选择
移动端点击没反应,console 报 DOMException: play() failed?
这是浏览器策略拦截,不是代码写错。所有现代移动端浏览器都强制要求 play() 必须由用户直接手势触发(click、touchstart),且不能被异步链打断。
- 绝对不要在
fetch().then()、setTimeout()、Promise.all()里调audio.play() - 如果需要加载完再播,把
audio.play()放在click回调最深处,中间不要穿插异步操作 - 本地开发时别用
file://协议打开 HTML——Chrome 直接禁音频;改用python3 -m http.server或 HBuilder X 内置服务器 - 安卓某些 WebView 会隐藏控件,加
controlsList="nodownload noplaybackrate"可保按钮可见
如何让当前播放项高亮并同步更新时间显示?
高亮靠 DOM 类切换,时间更新靠事件节流——这两件事看似简单,但容易因频繁操作拖垮性能或出现状态错乱。
立即学习“前端免费学习笔记(深入)”;
- 每次新歌播放前,先移除旧
li.playing类,再给当前li加上;别依赖audio.src字符串匹配,用data-id更可靠 -
timeupdate事件每秒触发 4–60 次,直接更新textContent会卡 UI;用requestAnimationFrame或 250ms 节流即可 - 显示格式如
"02:15 / 03:42",需自己写formatTime(seconds)函数,别用audio.duration原始值——它可能为Infinity或NaN - 进度条
value更新也得节流,否则滑块会抖动;且拖动时要临时禁用timeupdate自动更新,避免冲突
play() 必须带用户手势、Android WebView 对 preload 的诡异解析、还有 MP3 文件里藏的 ID3v2.4 标签会让部分浏览器拒绝解码——这些没法靠查文档一眼发现,只能靠真机反复试。



















