当前位置: 首页 > 面试题库 >

在reactjs中播放声音

朱修真
2023-03-14
问题内容
import React, { Component } from 'react'
import { Button, Input, Icon,Dropdown,Card} from 'semantic-ui-react'
import { Link } from 'react-router-dom'
import $ from 'jquery'
import styles from './Home.scss'
import Modal from './Modal.jsx'
import MakeChannelModal from './MakeChannelModal.jsx'

class Music extends React.Component {
    constructor(props) {
    super(props);
    this.state = {

      play: false,
      pause: true

    };

    this.url = "http://streaming.tdiradio.com:8000/house.mp3";
    this.audio = new Audio(this.url);

  }

  play(){
    this.setState({
      play: true,
      pause: false
    });
    console.log(this.audio);
    this.audio.play();
  }

  pause(){
  this.setState({ play: false, pause: true });
    this.audio.pause();
  }

  render() {

  return (
    <div>
      <button onClick={this.play}>Play</button>
      <button onClick={this.pause}>Pause</button>
    </div>
    );
  }
}


export default Music

这是我用来在我的react应用程序中使用url(this.url)播放声音的代码。当我按下播放按钮时,它给我一个错误

Uncaught TypeError: Cannot read property 'setState' of undefined

我不确定为什么会这样,因为我没有看到任何未定义的状态。一个;; 状态已经声明。

我是新来的反应者,所以我可能会错过一些非常重要的东西。

请帮忙!


问题答案:

我稍微改进了Jaxx的版本,使其包含一个,eventListener以便在音频结束时重置按钮。

ES6类属性语法

class Music extends React.Component {
  state = {
    play: false
  }
  audio = new Audio(this.props.url)

  componentDidMount() {
    audio.addEventListener('ended', () => this.setState({ play: false }));
  }

  componentWillUnmount() {
    audio.removeEventListener('ended', () => this.setState({ play: false }));  
  }

  togglePlay = () => {
    this.setState({ play: !this.state.play }, () => {
      this.state.play ? this.audio.play() : this.audio.pause();
    });
  }

  render() {
    return (
      <div>
        <button onClick={this.togglePlay}>{this.state.play ? 'Pause' : 'Play'}</button>
      </div>
    );
  }
}

export default Music;

挂钩版本(反应16.8+):

import React, { useState, useEffect } from "react";

const useAudio = url => {
  const [audio] = useState(new Audio(url));
  const [playing, setPlaying] = useState(false);

  const toggle = () => setPlaying(!playing);

  useEffect(() => {
      playing ? audio.play() : audio.pause();
    },
    [playing]
  );

  useEffect(() => {
    audio.addEventListener('ended', () => setPlaying(false));
    return () => {
      audio.removeEventListener('ended', () => setPlaying(false));
    };
  }, []);

  return [playing, toggle];
};

const Player = ({ url }) => {
  const [playing, toggle] = useAudio(url);

  return (
    <div>
      <button onClick={toggle}>{playing ? "Pause" : "Play"}</button>
    </div>
  );
};

export default Player;

更新03/16/2020:多个并发玩家

回应@Cold_Class的评论:

不幸的是,如果我使用这些组件中的多个组件,则当我开始播放另一个组件时,来自其他组件的音乐不会停止播放-关于此问题的简单解决方案有何建议?

不幸的是,没有使用我们用来实现单个Player组件的确切代码库的简单解决方案。原因是您必须以某种方式将单个播放器状态提升到MultiPlayer父组件,以便该toggle功能能够暂停与您直接交互的播放器以外的其他播放器。

一种解决方案是修改挂钩本身,以同时管理多个音频源。这是一个示例实现:

import React, { useState, useEffect } from 'react'

const useMultiAudio = urls => {
  const [sources] = useState(
    urls.map(url => {
      return {
        url,
        audio: new Audio(url),
      }
    }),
  )

  const [players, setPlayers] = useState(
    urls.map(url => {
      return {
        url,
        playing: false,
      }
    }),
  )

  const toggle = targetIndex => () => {
    const newPlayers = [...players]
    const currentIndex = players.findIndex(p => p.playing === true)
    if (currentIndex !== -1 && currentIndex !== targetIndex) {
      newPlayers[currentIndex].playing = false
      newPlayers[targetIndex].playing = true
    } else if (currentIndex !== -1) {
      newPlayers[targetIndex].playing = false
    } else {
      newPlayers[targetIndex].playing = true
    }
    setPlayers(newPlayers)
  }

  useEffect(() => {
    sources.forEach((source, i) => {
      players[i].playing ? source.audio.play() : source.audio.pause()
    })
  }, [sources, players])

  useEffect(() => {
    sources.forEach((source, i) => {
      source.audio.addEventListener('ended', () => {
        const newPlayers = [...players]
        newPlayers[i].playing = false
        setPlayers(newPlayers)
      })
    })
    return () => {
      sources.forEach((source, i) => {
        source.audio.removeEventListener('ended', () => {
          const newPlayers = [...players]
          newPlayers[i].playing = false
          setPlayers(newPlayers)
        })
      })
    }
  }, [])

  return [players, toggle]
}

const MultiPlayer = ({ urls }) => {
  const [players, toggle] = useMultiAudio(urls)

  return (
    <div>
      {players.map((player, i) => (
        <Player key={i} player={player} toggle={toggle(i)} />
      ))}
    </div>
  )
}

const Player = ({ player, toggle }) => (
  <div>
    <p>Stream URL: {player.url}</p>
    <button onClick={toggle}>{player.playing ? 'Pause' : 'Play'}</button>
  </div>
)


export default MultiPlayer

App.js使用MultiPlayer组件的示例:

import React from 'react'
import './App.css'
import MultiPlayer from './MultiPlayer'

function App() {
  return (
    <div className="App">
      <MultiPlayer
        urls={[
          'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3',
          'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3',
          'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-3.mp3',
        ]}
      />
    </div>
  )
}

export default App

这个想法是管理2个并行数组:

  • 您的音频源(由urls传递给父组件的urls道具构建;道具是字符串数组(您的MP3 URL))
  • 跟踪每个玩家状态的数组

toggle方法根据以下逻辑更新播放器状态数组:

  • 如果当前有一个正在播放的播放器(即正在播放音频),并且该活动播放器不是toggle方法所针对的播放器,则将该播放器的播放状态恢复为false,然后将目标播放器的播放状态设置为true [您单击了’play ‘,而 另一个 音频流已经在播放中]
  • 如果当前活动的玩家是使用toggle方法定位的玩家,则只需将目标玩家的播放状态恢复为假[您点击了“暂停”
  • 如果当前没有播放器处于活动状态,则只需将目标播放器的状态设置为true [您没有播放音频流时单击“播放”即可]

注意,该toggle方法被强制接受源播放器的索引(即,单击相应按钮的子组件的索引)。

实际的音频对象控制useEffect与原始钩子一样发生,但是稍微复杂一些,因为我们每次更新都必须遍历整个音频对象数组。

类似地,音频流“结束”事件的事件侦听器将在第二秒内进行处理,useEffect就像在原始钩子中一样,但是会更新以处理音频对象数组,而不是单个此类对象。

最后,从上级MultiPlayer组件(容纳多个播放器)中调用新的钩子,然后Player使用(a)一个包含播放器当前状态及其源流URL的对象,以及(b)使用玩家指数。

CodeSandbox演示



 类似资料:
  • 播放(播放音效/播放录音)

  • 问一下Xamarin.Forms便携里面Xamarin.Forms的音频怎么播放 正如我所知,有依赖服务,我看到了一些示例,只有iOS和Android,但没有Windows Phone 8.1/Windows 8.1和UWP。

  • 问题内容: 我经常在IPython笔记本中运行长时间运行的单元。我希望笔记本计算机在单元执行完后自动发出蜂鸣声或播放声音。在iPython笔记本中是否可以执行某些操作,或者可以在可以自动播放声音的单元格的末尾添加一些命令? 如果这有任何区别,我正在使用Chrome。 问题答案: TL; DR 在笔记本顶部 应该指向您计算机上的文件,或者可以从Internet访问。 然后,在长时间运行的单元结束时

  • 问题内容: 我正在尝试使用pygame播放声音文件(.wav),但是当我启动它时却听不到任何声音。 这是代码: 我也尝试使用频道,但结果是一样的 问题答案: 您的代码在我的机器上可以正常运行(Mac OSX 10.5,Python 2.6.4,pygame 1.9.1)。您正在使用哪些OS,Python和pygame版本?您是否可以通过其他方式(例如,在Mac的终端上或在Windows控制台上,然

  • 问题内容: 以下代码为什么不播放声音?它为play()返回“ true”,但我听不到任何声音。 如果我改用以下代码,则可以听到声音。 OS X优胜美地10.10.3 Xcode 6.2 问题答案: 问题是,您的AVAudioPlayer是一个 局部变量 。因此,它会立即不复存在-在开始播放之前,更不用说完成播放了。 解决方案:改为将其设置为 属性 ,以使其 持久存在 。

  • 问题内容: Octave似乎假设某个特定的声音播放实用程序将在系统上可用,但似乎没有提供指定备用声音的功能。在以下错误中,Octave正在寻找,这不是在所有系统上都可用的实用程序。 八度:38>声音(beamformed_20) sh:ofsndplay:找不到命令 是否可以使用Octave配置设置或代码片段来指定适合系统的实用程序? 问题答案: 在我的一台Linux机器上,我创建了以下ofsnd