直接用 window.speechsynthesis 可离线语音合成,但需监听 voiceschanged 确保语音引擎就绪;必须显式设置 utterance.lang = 'zh-cn' 等参数;暂停/停止需区分 pause()/resume() 与 cancel();ios/safari 要求用户交互后才可用,微信 x5 内核默认禁用。

直接用 window.speechSynthesis 就能实现,不依赖任何库、不发请求、离线可用——但前提是用户浏览器支持 Web Speech API,且语音引擎已加载完成。
speechSynthesis.speak() 调用前必须等 voicesready
常见错误是页面一加载就调用 speak(),结果没声音、也没报错。这是因为 window.speechSynthesis.getVoices() 初次返回空数组:语音列表异步加载,需监听 voiceschanged 事件。
- 不要在
DOMContentLoaded里直接getVoices()后就 speak —— 大概率失败 - 正确做法:先监听
speechSynthesis.onvoiceschanged,或主动轮询getVoices().length是否非零 - Chrome/Edge 通常 100–300ms 内就 ready;Safari(macOS/iOS)部分版本需用户首次交互后才触发加载,此时需 fallback 提示
SpeechSynthesisUtterance 配置项影响实际效果
默认语速、音调、语言都走系统偏好,但中文朗读常因 language 未显式指定而变英文或发音生硬。
-
utterance.lang = 'zh-CN'必设,否则 Chrome 可能用 en-US 语音读中文(吐字含糊) -
utterance.rate = 0.9(范围 0.1–10):设为 >1 容易吞字,中文建议 0.8–1.1 -
utterance.pitch = 1(0–2):过高像机器人,过低沉闷,中文默认 1 即可 -
utterance.volume = 1(0–1):某些安卓 WebView 下 volume=0 仍会漏声,慎设 0
暂停/停止/重播逻辑容易混乱
speechSynthesis.pause() 和 stop() 行为不同,且多次调用 speak() 会排队,不是覆盖。
-
pause()暂停当前 utterance,再调resume()可继续;但若 utterance 已结束,resume 无效 -
stop()清空整个语音队列,包括尚未开始的 utterance,且当前正在播的会立即中断 - 重播前务必
speechSynthesis.cancel()(等价于 stop),否则新 utterance 会排在旧队列后面 - 没有“播放中”状态变量?别只靠
speechSynthesis.pending,它不反映是否正在发声,要用onstart/onend事件维护 state
移动端和 Safari 的兼容性坑最深
iOS Safari 完全不支持自动播放语音,必须由用户真实点击(touchstart 或 click)触发;且首次调用前需用户与页面有交互(比如点过按钮、输过文字)。
- Android Chrome 一般正常;但某些定制 ROM(如华为 EMUI 内置浏览器)可能禁用 Web Speech API
- Safari 中
getVoices()在无用户交互时返回空数组,且voiceschanged不触发 —— 必须把首次 speak 绑定到按钮 click 回调里 - 微信内置浏览器(X5 内核)默认禁用该 API,无法绕过;需提示“请在 Safari 或 Chrome 中打开”
- 别用
setTimeout模拟用户点击来 hack,iOS 会识别为非可信事件,直接忽略
真正难的不是写几行 speak(),而是处理语音引擎加载时机、跨浏览器行为差异、以及用户没给权限时的静默失败——这些地方不加 guard,功能在某些设备上就等于不存在。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











