You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 03:08:25