audio.play()必须在用户手势上下文中调用,如点击事件内直接执行;iOS Safari更严格,仅接受同步调用;需预加载、用短时WAV格式、手动控制循环并注意静音开关影响。

audio.play() 必须在用户手势上下文中调用
浏览器(Chrome/Firefox/Safari/iOS Safari)默认禁止自动播放音频,哪怕你写了 autoplay 或在 DOMContentLoaded 里调 play(),也会静音或抛出 NotAllowedError。这不是代码写错,是策略限制。
真正能触发声音的前提只有一个:用户已与页面发生真实交互,比如点击按钮、触摸屏幕、按普通按键(非 Ctrl/Meta 等修饰键)。
- ✅ 正确写法:
button.addEventListener('click', () => alarmAudio.play()) - ❌ 错误写法:
fetch('/api/status').then(() => alarmAudio.play())—— 浏览器判定为“非手势上下文”,直接拒绝 - ⚠️ iOS Safari 更严格:连
setTimeout(() => play(), 0)或Promise.resolve().then(play)都不认,必须同步执行
用 new Audio() 预加载,别依赖
标签加 preload="auto" 在移动端常被忽略,且会阻塞 HTML 解析;而 new Audio(src) + .load() 是更可控的预加载方式。
首次 .play() 时若未加载完成,会出现明显延迟(尤其 MP3 >200KB 时),用户点完没反应,体验断裂。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 提前实例化:
const alarmAudio = new Audio('alarm.wav'); - 页面加载后立即预加载:
alarmAudio.load();(不调play()) - 推荐格式:短时
.wav(1–3 秒,44.1kHz 单声道 PCM),启动快、无解码失败风险;MP3 可用但需压缩到80–120KB内 - 避免带 ID3 元数据的 MP3,部分 Android WebView 会因解析失败导致
play()拒绝执行
循环报警别用 loop 属性,监听 ended 手动重播
loop 属性在某些安卓 WebView 和旧版 iOS 中不可靠,可能播一次就停,或无法响应暂停/重置。
手动控制更稳妥,还能插入逻辑(如限制最大播放次数、配合视觉闪烁)。
- 设置循环:
alarmAudio.onended = () => { alarmAudio.currentTime = 0; alarmAudio.play(); }; - 停止时记得清理:
alarmAudio.pause(); alarmAudio.currentTime = 0; - 若需“响 5 秒停 2 秒再响”,不要用多个
setTimeout嵌套,改用requestAnimationFrame或setInterval控制状态机
告警音效本身要短、高频、有辨识度
别用 30 秒警笛 MP3。真实场景下,“立刻感知异常”比“听完整段音效”重要得多。长音频不仅加载慢、解码慢,还容易被用户误关或掩盖。
- 推荐时长:1–3 秒
- 推荐波形:方波类高频脉冲(如 800–1200Hz)、带明显起音(attack)的 beep 声,比正弦波更容易穿透环境噪音
- 可用 Audacity 导出为
WAV (Microsoft) signed 16-bit PCM,体积小、兼容性好、无编解码开销 - 测试时务必打开手机物理静音开关、检查系统音量,iOS Safari 下静音开关关闭会导致所有 Web 音频静音(即使 JS 设置了
volume = 1)
关键点不在“怎么放声音”,而在“什么时候能放”和“放得是否可靠”。很多项目卡在第一次点不动,其实是没意识到 play() 调用栈必须紧贴原生事件回调——中间插一个 Promise、一个 await、甚至一个 console.log,都可能破坏手势上下文链。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










