使用React播放音频

7

无论我做什么,在尝试播放声音时都会收到错误消息:

未捕获(在承诺中)DOM异常。

在Google上搜索后,我发现如果在用户对页面进行任何操作之前自动播放音频,则应该出现此错误消息,但这对我不适用。我甚至尝试了这个方法:

componentDidMount() {
  let audio = new Audio('sounds/beep.wav');
  audio.load();
  audio.muted = true;
  document.addEventListener('click', () => {
    audio.muted = false;
    audio.play();
  });
}

但是提示仍然出现,声音无法播放,我该怎么办?


“sounds/beep.wav” 这个文件在服务器上存在吗?你确定相对路径是正确的吗? - Alexander Elgin
如果您将前三行语句放在事件处理程序的开头,错误消息是否仍然存在?如果您将事件处理程序删除并将audio.play()放在componentDidMount的末尾,它是否仍然存在? - Alexander Elgin
可能是重复的问题,来源于https://dev59.com/RVkS5IYBdhLWcg3wKjr1。请参考该链接。 - Nico Diz
该文件存在于“服务器”上。那是我的电脑,我将其放在/src/sounds文件夹和/src中的App.js中。 我不知道它是否重复。我不想自动播放,它应该在用户点击后播放。虽然我也尝试过这样做,但我能捕获到错误,但我该怎么办? - Henrik Hollósi
错误仍然存在于componentDidMount() { document.addEventListener("click", () => { let audio = new Audio("sounds/beep.wav"); audio.load(); audio.play(); }) } - Henrik Hollósi
顺便说一下,我正在尝试完成这个项目:https://learn.freecodecamp.org/front-end-libraries/front-end-libraries-projects/build-a-pomodoro-clock。我看了一下解决方案,但是似乎也无法按照那个工作...我尝试使用refs,但没有成功。 - Henrik Hollósi
4个回答

7
音频是一个HTMLMediaElement,调用play()会返回一个Promise,因此需要处理。根据文件的大小,它通常已准备就绪,但如果没有加载(例如挂起的Promise),它将抛出“AbortError”DOM异常。
您可以先检查是否已加载,然后捕获错误以关闭消息。例如:
componentDidMount() {
      this.audio = new Audio('sounds/beep.wav')
      this.audio.load()
      this.playAudio()
}

playAudio() {
    const audioPromise = this.audio.play()
    if (audioPromise !== undefined) {
      audioPromise
        .then(_ => {
          // autoplay started
        })
        .catch(err => {
          // catch dom exception
          console.info(err)
        })
    }
}

另一个有效的模式是将组件创建为带有“autoPlay”属性的“HTML音频元素”,然后根据需要呈现它作为组件。例如:

const Sound = ( { soundFileName, ...rest } ) => (
  <audio autoPlay src={`sounds/${soundFileName}`} {...rest} />
)

const ComponentToAutoPlaySoundIn = () => (
   <>
     ...
     <Sound soundFileName="beep.wav" />
     ...
   </>
)

是的,我已经尝试过了,我能够捕获错误并且console.log显示“DOMException”。有时我不得不点击两次才能使console.log出现。如果我在then分支中使用console.log,则什么也不会出现。音频从未开始。我还尝试在另一个组件中呈现它。 - Henrik Hollósi
@HenrikHollósi 好的,所以你有一个元素(我们称之为按钮),当你点击它时,它应该播放本地/静态声音而不显示任何错误。是这样吗?还是其他功能?我将进行更新。 - marsheth
没错,基本上就是这样。它还有一个逻辑,即按钮应该启动一个计时器,倒数到零时播放音频。 - Henrik Hollósi
所以,我尝试了你的解决方案,发现问题与链接有关。如果我提供自己的文件,会出现“DOMException”错误,并记录承诺的消息:“该元素没有受支持的源”。如果我使用来自外部来源(如你提供的链接)的声音,则可以正常工作。我非常确定我使用的是有效的URL,已经反复检查过了。也许我不能使用从soundbible下载的声音文件。 - Henrik Hollósi
@HenrikHollósi 这似乎是一个 CORS 问题。我们导入一下,这样就能确保它可以读取了吧?使用上传的文件,这对我来说是可行的(抱歉 beep 声音短且有些恼人 lol):在 Sandbox 中使用上传的文件播放音频 - marsheth
显示剩余2条评论

1

简单的错误提示音

如果您想要像在条形码扫描环境中一样,以非视觉反馈的方式播放简单的错误提示音,并且不想安装任何依赖项等 - 这可以非常简单。只需链接到您的音频文件:

import ErrorAudio from './error.mp3'

在代码中引用它并播放:
var AudioPlay = new Audio (ErrorAudio);
AudioPlay.play();

在尝试更复杂的选项后才发现这个简单方法。


1
很棒的答案! 通常情况下,最好的解决方案可以在原生JavaScript中找到。 - Dustin Halstead

0

这非常简单

const [, setMuted] = useState(true)

useEffect(() => {
  const player = new Audio(./sound.mp3);
  const playPromise = player.play();
  if (playPromise !== undefined) 
      return playPromise.then(() => setMuted(false)).catch(() => setMuted(false));
}, [])

希望现在它能正常工作 :)


0

依旧一样。我的代码和那个组件看起来像这样:function() { this.refs.audioEl.pause(); this.refs.audioEl.currentTime = 0; this.refs.audioEl.play(); } render(){ return( { this.refs = element; }} autoPlay /> ) } - Henrik Hollósi
你可能应该像这个例子(https://github.com/justinmc/react-audio-player/blob/master/example/js/main.jsx)一样使用`controls`属性来控制音乐,而不是使用引用。 - Kirill Novikov
添加了控件,但仍然是一样的。音频播放器呈灰色。我不想显示控件,音频应该在单击站点的其他组件时播放。 - Henrik Hollósi
如果我需要分配新的URL,我该怎么办? - K.S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接