我目前正在做一个网络项目,使用SpeechSynthel API来阅读网页上的文本段落.我一直在努力使口语单词与文本中的 colored颜色 变化保持同步,但我面临着一些挑战.

以下是对这一问题的简要概述:

  • I have a function that reads out the content of

    标签在页面上使用SpeechSynthesis API.

  • 我们的目标是实时同步说出的单词和 colored颜色 变化.
  • 具体地说,我希望每个单词在发音时都变为红色,并在单词完成时恢复为原始 colored颜色 .
  • 每一次try 都导致整段文字变红.

我在没有同步的情况下工作的代码如下.

function speakAllParagraphs(page) {
  // Get all <p> elements within the current page
  var paragraphs = document
    .getElementById("page" + page)
    .getElementsByTagName("p");

  // Iterate through each <p> tag
  Array.from(paragraphs).forEach(function (paragraph, index) {
    // Speak the text of the paragraph
    var text = paragraph.innerText;

    // Create a new SpeechSynthesisUtterance
    var utterance = new SpeechSynthesisUtterance();
    utterance.text = text;

    // Find the voice by name
    const voices = speechSynthesis.getVoices();
    const targetVoice = voices.find(
      (voice) =>
        voice.name === "Microsoft Emily Online (Natural) - English (Ireland)"
    );

    if (targetVoice) {
      utterance.voice = targetVoice;
    } else {
      // Fallback: if the target voice is not available, use default voice
      utterance.voice = voices[0];
    }

    // Play the synthesized speech
    speechSynthesis.speak(utterance);
  });
}
  • 我try 使用ONBERIAL事件来更改单个单词的 colored颜色 ,但它没有按预期工作.
  • 我try 了几种方法,包括使用计时器和事件,但未能实现所需的同步.
  • 每一次try 都导致整段文字变红.
  • 我们的目标是让每个单词在说出时变成红色,并在单词完成时恢复到原始 colored颜色 .

推荐答案

您可以通过监听SpeechSynthesisUtterance实例上的boundary事件来完成所需的行为.此事件将为您提供charIndexcharLength属性,该属性将指示在该特定时刻发声在字符串中的位置.

这允许您从字符串中抓取特定部分并将其包装在HTML中-就像下面示例中的<mark>标记-以突出显示当前的口语文本.将段落的文本替换为包含突出显示的文本.

另外,也要收听end事件,以便在发声结束时恢复段落中的原始文本.

const target = document.querySelector('p');

function speakAndHighlightText(target) {
  const text = target.textContent;
  const utterance = new SpeechSynthesisUtterance();
  utterance.text = text;
  
  utterance.addEventListener('boundary', ({ charIndex, charLength }) => {    
    const beforeWord = text.slice(0, charIndex);
    const word = text.slice(charIndex, charIndex + charLength);
    const afterWord = text.slice(charIndex + charLength, text.length);
    
    target.innerHTML = `${beforeWord}<mark>${word}</mark>${afterWord}`
  });
  
  utterance.addEventListener('end', event => {
    target.textContent = text;
  });
  
  speechSynthesis.speak(utterance);
}

speakAndHighlightText(target);
mark {
  background-color: red;
}
<html lang="en">
  <p>"Sunsets paint the sky with hues of warmth, a daily masterpiece. Nature's farewell kiss, fleeting yet timeless, whispers serenity to all."</p>
</html>

我还包含了一个处理多个段落的片段.这里的区别在于,speakAndHighlightText返回一个Promise,它解决了end事件,这归结为我们可以在移动到下一段之前完成await演讲.

const targets = document.querySelectorAll('p');

const speakAndHighlightText = (target) => new Promise(resolve => {
  const text = target.textContent;
  const utterance = new SpeechSynthesisUtterance();
  utterance.text = text;
  
  utterance.addEventListener('boundary', ({ charIndex, charLength }) => {    
    const beforeWord = text.slice(0, charIndex);
    const word = text.slice(charIndex, charIndex + charLength);
    const afterWord = text.slice(charIndex + charLength, text.length);
    
    target.innerHTML = `${beforeWord}<mark>${word}</mark>${afterWord}`
  });
  
  utterance.addEventListener('end', event => {
    target.textContent = text;
    resolve(target);
  });
  
  speechSynthesis.speak(utterance);
});

(async () => {
  for (const target of targets) {
    await speakAndHighlightText(target);
  }
  
  console.log('Finished speaking');
})();
mark {
  background-color: red;
}
<html lang="en">
  <p>"Sunsets paint the sky with hues of warmth, a daily masterpiece. Nature's farewell kiss, fleeting yet timeless, whispers serenity to all."</p>
  
  <p>Raindrops dance on leaves, a liquid symphony. Earth sighs in relief, embracing each droplet's embrace. Nature's lullaby, calming and pure.</p>
</html>

Javascript相关问答推荐

将json数组项转换为js中的扁平

如何访问Json返回的ASP.NET Core 6中的导航图像属性

如何判断属于多个元素的属性是否具有多个值之一

调用removeEvents不起作用

在JavaScript中声明自定义内置元素不起作用

我应该绑定不影响状态的函数吗?'

如何使用子字符串在数组中搜索重复项

无法避免UV:flat的插值:非法使用保留字"

将基元传递给THEN处理程序

在Odoo中如何以编程方式在POS中添加产品

Phaser3 preFX addGlow不支持zoom

将多个文本框中的输出合并到一个文本框中

是否可以在不更改组件标识的情况下换出Reaction组件定义(以维护状态/引用等)?如果是这样的话,是如何做到的呢?

ComponentWillReceiveProps仍在React 18.2.0中工作

使用Perl Selify::Remote::Driver执行Java脚本时出错

计算对象数组中属性的滚动增量

如何用react组件替换dom元素?

JSON Web令牌(JWT)错误:RSA密钥对的签名无效

使用JAVASCRIPT-使用If和Else If多次判断条件-使用JAVASRIPT对象及其属性

我正在为我的单选按钮在HTML中设置一个值.使用Java脚本,我如何才能获得该值?