- 前端
【免费下载链接】vueuse
Collection of essential Vue Composition Utilities for Vue 3
导读
useSpeechRecognition是 VueUse 提供的一个响应式组合式函数,它将浏览器原生的 SpeechRecognition,并结合 核心实现源码、类型定义、在线演示 与 测试用例,完整讲解其 API 形态、配置选项、底层工作原理与实战写法,读完即可在自己的 Vue 3 项目中接入语音识别能力。
一、功能定位与适用场景
SpeechRecognition API 允许网页将用户的语音实时转录为文本,但由于该 API 长期未进入稳定规范,各浏览器实现差异较大(Chrome 系浏览器支持SpeechRecognition或带前缀的webkitSpeechRecognition,部分浏览器完全不支持)。VueUse 的useSpeechRecognition正是为抹平这一差异而设计:
- 统一能力检测:自动探测
window.SpeechRecognition或window.webkitSpeechRecognition,并通过isSupported暴露支持状态; - 响应式状态:将
isListening、isFinal、result、confidence、error等回调结果转为 Vue 的 shallowRef,可直接在模板与组合式逻辑中绑定; - 生命周期自动管理:组件卸载时自动停止识别,避免资源泄漏。
该函数归类于 VueUse 的Sensors(传感器)类别,与useBattery、useGeolocation等浏览器能力封装同属一个体系,通过 core 包入口 导出。
浏览器兼容性提示:语音识别能力高度依赖浏览器与语音服务可用性,正式发布前建议通过
isSupported做降级处理,具体支持矩阵可参考 caniuse 中SpeechRecognition相关条目。
二、快速开始:最小可用示例
参考文档给出的最小用法如下:
import { useSpeechRecognition } from '@vueuse/core' const { isSupported, isListening, isFinal, result, confidence, start, stop, } = useSpeechRecognition()配合模板即可实现“点击开始/停止、实时显示转录文本”的最简交互:
<template> <div> <p v-if="!isSupported">当前浏览器不支持 SpeechRecognition</p> <template v-else> <button @click="isListening ? stop() : start()"> {{ isListening ? '停止' : '开始说话' }} </button> <p>识别结果:{{ result }}</p> <p v-if="isFinal">本轮已结束</p> </template> </div> </template>这段代码中所有返回值都来自useSpeechRecognition()的解构,其中result、isFinal等是响应式引用,会随语音识别事件的到来自动更新,无需手动维护回调。
三、返回对象全解析
根据 index.ts 的返回值定义 与 类型声明(UseSpeechRecognitionReturn),完整返回对象如下:
| 属性 | 类型 | 说明 |
|---|---|---|
isSupported | ComputedRef<boolean> | 当前环境是否支持语音识别(来自Supportable基接口) |
isListening | ShallowRef<boolean> | 是否正在监听语音 |
isFinal | Readonly<ShallowRef<boolean>> | 最新一条结果是否为最终结果(非临时结果) |
recognition | SpeechRecognition \| undefined | 底层识别器实例,可用于设置 grammars 等额外配置 |
result | Readonly<ShallowRef<string>> | 最新识别的转录文本 |
confidence | Readonly<ShallowRef<number>> | 最新结果的置信度,取值区间 0~1 |
error | ShallowRef<SpeechRecognitionErrorEvent \| Error \| undefined> | 最近一次错误事件或异常对象 |
toggle | (value?: boolean) => void | 切换监听状态,可显式传入布尔值 |
start | () => void | 开始识别 |
stop | () => void | 停止识别 |
几个需要重点理解的状态:
confidence(置信度):参考文档特别指出,该 ref 追踪的是“最新结果”的置信度,数值范围 0~1,对应 Web API 中SpeechRecognitionAlternative.confidence。置信度越高表示识别引擎对结果越有把握,可用于过滤低质量识别(例如低于 0.5 的结果提示用户重说)。其默认初始值为 0,见 index.ts#L77。
isFinal与result的配合:当interimResults: true时,识别过程中会不断产生临时结果,此时isFinal为false;当一段语音结束、产生最终结果时isFinal变为true。因此一个常见的模式是:只把isFinal === true时的result提交到业务逻辑,避免把中间过程的不稳定文本当真。
error:既可能是原生SpeechRecognitionErrorEvent(含error码与message),也可能是底层start()/stop()调用抛出的普通Error(见 index.ts#L151-L153)。
四、配置选项(Options)
参考文档明确指出:以下选项的默认值会直接透传给原生SpeechRecognition实例。默认配置示例如下:
import { useSpeechRecognition } from '@vueuse/core' useSpeechRecognition({ lang: 'en-US', interimResults: true, continuous: true, })完整选项定义见 UseSpeechRecognitionOptions,整理如下:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
continuous | boolean | true | 是否连续返回多轮识别结果,还是只返回单条结果(对应原生continuous) |
interimResults | boolean | true | 是否返回尚未定稿的临时结果(对应原生interimResults) |
lang | MaybeRefOrGetter<string> | 'en-US' | 识别语言,支持传入 ref/getter 实现响应式切换(对应原生lang) |
maxAlternatives | number | 1 | 每条结果最多返回几个候选,对应原生maxAlternatives |
window | Window | defaultWindow | 自定义window实例(来自ConfigurableWindow),用于 iframe 或测试环境注入 |
关于各选项在源码中的落地,可见 index.ts#L65-L71 的解构默认值,以及 index.ts#L105-L108 中将这些值写入识别器实例的代码:
const { interimResults = true, continuous = true, maxAlternatives = 1, window = defaultWindow, } = options const lang = toRef(options.lang || 'en-US') // ... recognition.continuous = continuous recognition.interimResults = interimResults recognition.lang = toValue(lang) recognition.maxAlternatives = maxAlternativeslang的响应式特性
lang是五个选项中唯一支持MaybeRefOrGetter(即string/Ref/Getter)的类型。源码用toRef将其规范化后,通过watch(lang, ...)监听:仅在未监听语音时才把新语言写入识别器(见 index.ts#L115-L118)。这是有意的设计——语音识别进行中修改语言会破坏当前会话,因此需要先stop()再切换语言,下一次start()即使用新语言。
watch(lang, (lang) => { if (recognition && !isListening.value) recognition.lang = lang })window的可注入性
window选项继承自 ConfigurableWindow 接口,这在 VueUse 中是通用的测试与隔离手段。默认取defaultWindow(客户端环境下即window,见 _configurable.ts#L39)。测试文件正是利用这一点注入 Mock 实例(详见下文“测试验证”)。
五、源码级原理:从调用到事件的完整链路
useSpeechRecognition的实现思路非常清晰:以 Vue 的响应式状态为“数据中枢”,用原生 API 的事件回调驱动这些状态,再用watch把状态的改变反向翻译为对原生 API 的调用。全流程如下:
1. 能力检测(isSupported)
const SpeechRecognition = window && (window.SpeechRecognition || window.webkitSpeechRecognition) const isSupported = useSupported(() => SpeechRecognition)通过 useSupported 将检测结果包装为计算属性,同时兼容带webkit前缀的实现。isSupported继承自Supportable接口(见 core 类型定义),是整个函数的“能力开关”。
2. 实例创建与初始化
if (isSupported.value) { recognition = new SpeechRecognition() as SpeechRecognition recognition.continuous = continuous recognition.interimResults = interimResults recognition.lang = toValue(lang) recognition.maxAlternatives = maxAlternatives }仅在支持时才创建实例,避免在不支持的浏览器上抛错。
3. 事件回调 → 响应式状态
四个关键回调把原生事件翻译为 ref 更新(index.ts#L110-L137):
onstart:置isListening = true、重置isFinal = false;onresult:取event.results[event.resultIndex]的首个候选,解构出transcript与confidence,分别写入result、confidence,isFinal由currentResult.isFinal决定,同时清空error;onerror:把SpeechRecognitionErrorEvent写入error;onend:置isListening = false,并恢复recognition.lang为当前lang值。
4. 响应式状态 → 原生调用(反向联动)
watch(isListening, (newValue, oldValue) => { if (newValue === oldValue) return try { if (newValue) recognition!.start() else recognition!.stop() } catch (err) { error.value = err as unknown as Error } })当isListening变化时触发start()/stop(),并把可能抛出的异常捕获到error。这意味着你不需要直接调用recognition.start()——只需修改isListening(或调用start/stop/toggle这三个内部会改动isListening的函数)即可驱动底层,这正是start/stop实现如此简洁的原因(index.ts#L82-L97):
const start = () => { isListening.value = true } const stop = () => { isListening.value = false } const toggle = (value = !isListening.value) => { if (value) start() else stop() }5. 自动清理
tryOnScopeDispose(() => { stop() })组件卸载(或副作用作用域销毁)时自动停止识别,与 VueUse 其他组合式函数保持一致。
6. 完整类型支撑
由于 SpeechRecognition 属于实验性 API,仓库在 types.ts 中提供了完整的 TypeScript 类型补全,包括SpeechRecognition接口、事件映射SpeechRecognitionEventMap,以及错误码联合类型:
export type SpeechRecognitionErrorCode = | 'aborted' | 'audio-capture' | 'bad-grammar' | 'language-not-supported' | 'network' | 'no-speech' | 'not-allowed' | 'service-not-allowed'这些错误码恰好是你在处理error状态时可以用来做分支提示的枚举,例如'not-allowed'表示用户拒绝了麦克风权限、'network'表示网络错误等。
六、实战进阶:颜色口令识别(官方 Demo 拆解)
官方演示 demo.vue 是一个很好的综合示例:它利用JSGF 语法(SpeechGrammarList)限制识别词表,实现“说颜色名 → 界面变色”的交互。核心逻辑如下:
const colors = ['aqua', 'azure', 'beige', /* ... */] const grammar = `#JSGF V1.0; grammar colors; public <color> = ${colors.join(' | ')} ;` const speech = useSpeechRecognition({ lang, continuous: true, }) if (speech.isSupported.value) { // 浏览器存在前缀差异时做兼容 const SpeechGrammarList = window.SpeechGrammarList || window.webkitSpeechGrammarList const speechRecognitionList = new SpeechGrammarList() speechRecognitionList.addFromString(grammar, 1) speech.recognition!.grammars = speechRecognitionList // 监听转录结果,匹配颜色词 watch(speech.result, () => { for (const i of speech.result.value.toLowerCase().split(' ').reverse()) { if (colors.includes(i)) { color.value = i break } } }) }要点提炼:
- 自定义语法:通过
speech.recognition!.grammars直接操作底层实例(recognition暴露出来正是为了这类扩展场景),addFromString(grammar, 1)中的第二个参数是该语法的权重; - 语言实时切换:
lang用shallowRef('en-US')传入,配合模板中的单选按钮在en-US/fr/es间切换,切换后需重新开始识别才生效(Demo 中通过isListening联动更新已选语言文案); - 结果后处理:把
result分词、小写化后反向匹配词表,命中即更新 UI——说明result是一个可以被watch的普通响应式值。
七、测试验证:行为被测试锁定的部分
仓库为useSpeechRecognition提供了浏览器环境测试 index.browser.test.ts,它用createMockWindow()注入一个MockSpeechRecognition类来模拟原生 API,验证了以下行为:
- 函数可被正常定义与导出;
confidence初始值为0;- 触发
onresult事件后,result更新为'hello world'、confidence更新为0.85(同时验证了transcript与confidence的解构取数逻辑); - 无
window时仍保持返回结构完整:confidence.value === 0、result.value === ''、isListening.value === false,即 SSR / 非浏览器环境下不会抛错,只是能力不可用。
这意味着:如果你需要在自己的项目中为这个函数编写单元测试,同样可以借助window选项注入 mock,而不必依赖真实麦克风。
八、使用建议与注意事项
- 先检测后使用:模板中务必先渲染
isSupported为false的降级 UI(如 Demo 中提示“Your browser does not support SpeechRecognition API”); - 权限与安全:识别前浏览器会请求麦克风权限,
error为'not-allowed'时应引导用户开启权限;语音数据由浏览器/语音服务处理,涉及隐私场景需在页面内明示; - 语言切换需先停止:由于
watch(lang)只在!isListening时生效,切换lang前应先stop(); - 区分临时与最终结果:业务上一般以
isFinal === true为准,避免把识别过程中的中间文本提交; - 置信度阈值:
confidence在 0~1 之间,可结合场景设置阈值过滤低质量识别; - 生命周期:
tryOnScopeDispose保证组件卸载自动停止,无需手动清理,但长时间页面建议在不需要时显式stop()以节省资源。
小结
useSpeechRecognition用约 170 行代码,把实验性强、回调密集的 Web Speech API 封装成了“解构即用、状态响应式、生命周期自管理”的 Vue 组合式函数。本文涉及的关键文件均可继续深入研读:官方参考文档、核心实现、类型定义、演示源码 与 测试用例。若想了解其作为 Sensors 类函数的通用模式,可对比 useSupported 与 可配置 window 约定。
- 前端
【免费下载链接】vueuse
Collection of essential Vue Composition Utilities for Vue 3
相关推荐
VueUse 的 useSpeechRecognition:在 Vue 3 中把浏览器语音识别变成响应式状态
VueUse 的 useSpeechRecognition:在 Vue 3 中把浏览器语音识别变成响应式状态 导读 useSpeechRecognition 是
前端VueUse useShare 深度指南:在 Vue 3 中响应式封装 Web Share API
VueUse useShare 深度指南:在 Vue 3 中响应式封装 Web Share API 本文以 useShare/index.md https://
前端VueUse usePermission 完全指南:用 Vue 3 响应式封装 Web Permissions API
VueUse usePermission 完全指南:用 Vue 3 响应式封装 Web Permissions API 导读 usePermission 是 V
前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考