如何基于React语音识别库自动逐行高亮API返回的多行文本?
实现React中朗读文本时的逐行高亮自动切换
要解决逐行朗读并自动高亮切换的问题,核心是利用Web Speech API的事件监听判断行朗读完成,结合React状态管理更新高亮行ID。以下是两种可靠的实现方案:
方案1:逐行朗读+onend事件触发切换
这种方案逻辑简单、可靠性高,适合需要清晰分隔每行朗读的场景。
步骤1:状态与数据处理
在组件中定义状态,存储API获取的行数据、当前高亮行ID和朗读实例:
import { useState, useEffect } from 'react'; function TextReader() { const [lines, setLines] = useState([]); // 存储API返回的每行文本,格式如[{id: 1, text: "第一行"}, ...] const [currentHighlightedId, setCurrentHighlightedId] = useState(null); const [activeUtterance, setActiveUtterance] = useState(null); // 模拟从API获取数据 useEffect(() => { fetch('/your-api-endpoint') .then(res => res.json()) .then(data => setLines(data)) .catch(err => console.error('数据获取失败:', err)); }, []);
步骤2:实现逐行朗读逻辑
编写朗读函数,利用SpeechSynthesisUtterance的onend事件,在当前行朗读完成后自动切换到下一行:
const startReading = () => { // 停止正在进行的朗读 if (activeUtterance) { window.speechSynthesis.cancel(); } let currentLineIndex = 0; const readNextLine = () => { if (currentLineIndex >= lines.length) { setCurrentHighlightedId(null); return; } const targetLine = lines[currentLineIndex]; setCurrentHighlightedId(targetLine.id); const utterance = new SpeechSynthesisUtterance(targetLine.text); // 当前行朗读结束后,切换到下一行 utterance.onend = () => { currentLineIndex++; readNextLine(); }; window.speechSynthesis.speak(utterance); setActiveUtterance(utterance); }; readNextLine(); };
步骤3:渲染与高亮
通过map渲染每行文本,根据currentHighlightedId判断是否添加高亮样式:
return ( <div> <button onClick={startReading}>开始朗读</button> <div className="text-container"> {lines.map(line => ( <p key={line.id} className={currentHighlightedId === line.id ? 'highlighted' : ''} > {line.text} </p> ))} </div> </div> ); } export default TextReader;
高亮样式
添加CSS实现高亮效果:
.highlighted { background-color: #fff3cd; font-weight: 600; }
方案2:整段朗读+onboundary实时跟踪
如果需要连续朗读所有文本,同时实时高亮当前读到的行,可以利用onboundary事件跟踪朗读的字符位置,匹配到对应行后更新高亮。
核心逻辑修改
在useEffect中计算每行的字符范围,监听边界事件判断当前朗读行:
useEffect(() => { if (lines.length === 0) return; // 计算每行文本的字符起始/结束位置 const lineCharRanges = []; let currentCharPos = 0; lines.forEach(line => { const startPos = currentCharPos; const endPos = currentCharPos + line.text.length; lineCharRanges.push({ id: line.id, start: startPos, end: endPos }); currentCharPos += line.text.length + 1; // 加1是为了包含行之间的分隔符(如空格/换行) }); // 拼接所有文本为整段 const fullText = lines.map(line => line.text).join(' '); const utterance = new SpeechSynthesisUtterance(fullText); // 监听朗读边界事件,实时更新高亮行 utterance.onboundary = (e) => { const currentCharIndex = e.charIndex; const matchedLine = lineCharRanges.find(range => currentCharIndex >= range.start && currentCharIndex <= range.end ); if (matchedLine) { setCurrentHighlightedId(matchedLine.id); } }; utterance.onend = () => setCurrentHighlightedId(null); window.speechSynthesis.speak(utterance); setActiveUtterance(utterance); // 组件卸载时停止朗读 return () => window.speechSynthesis.cancel(); }, [lines]);
注意事项
- 浏览器兼容性:Web Speech API在Chrome、Edge中支持较好,Safari需要开启相关设置。
- 朗读控制:记得在组件卸载或重新触发朗读时,调用
speechSynthesis.cancel()清理之前的朗读实例。 - API数据格式:确保从API获取的每行数据包含唯一
id字段,用于高亮匹配和React渲染的key。
内容的提问来源于stack exchange,提问作者DoaaMostafa
相关产品推荐
相关产品推荐

