【问题标题】:Manage Multiple Audio Sources in React在 React 中管理多个音频源
【发布时间】:2018-06-02 00:41:13
【问题描述】:

我有一个 React 组件,当您单击按钮时,它会播放/暂停音频。它工作得很好,我一次在一个页面上渲染了大约 5 个。但是,如果您单击一个播放,然后单击另一个播放,则两个音频都在播放,这不是很好。这是我的组件代码:

import React from 'react';
import playIcon from './images/play.png';
import pauseIcon from './images/pause.png';
class Music extends React.Component {
    constructor(props) {
        super(props);
        this.state = { 'play': false };
        this.url = props.src;
        this.audio = new Audio(this.url);
        this.audio.preload = 'none';
        this.togglePlay = this.togglePlay.bind(this);
    }

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

    componentWillUnmount () {
        this.audio.pause();
    }

    render() {
        return (
            <div style={this.props.style} className={this.props.className}>
                {this.state.play
                    ? <button className="audio-button" aria-label="Pause" onClick={this.togglePlay}><img src={pauseIcon} width="34" height="34" alt="Pause"></img></button>
                    : <button className="audio-button" aria-label="Play" onClick={this.togglePlay}><img src={playIcon} width="34" height="34" alt="Play"></img></button>}
            </div>
        );
    }
}

export default Music;

我已经环顾四周,一个潜在的解决方案是使用 redux 或其他一些状态管理库。我想避免这种情况,否则我在这个网站上不需要。我查看了事件侦听器(即solution proposed here),但是当我执行document.getElementsByTagName('audio') 时,我得到一个空的HTMLCollectionThis solution 更接近,但我无法弥合它在 jQuery 中的实现与我在 React 中使用的实现之间的差距。

有没有办法在播放新音频之前识别正在播放的音频并从 React 组件暂停它?任何和所有的建议表示赞赏。

【问题讨论】:

  • 为什么音频不是组件?

标签: javascript reactjs audio


【解决方案1】:
import React from 'react';

import audio1 from './audio1.mp3';
import audio2 from './audio2.mp3';

class AudioList extends React.Component {
    constructor (props) {
        super(props);

        this.audios = props.list.map(audio => new Audio(audio));
    }

    getCurrentAudio () {
        return this.audios.find(audio => false === audio.paused);
    }

    toggle (nextAudio) {
        const currentAudio = this.getCurrentAudio();

        if (currentAudio && currentAudio !== nextAudio) {
            currentAudio.pause();
        }

        nextAudio.paused ? nextAudio.play() : nextAudio.pause();
    }

    render () {
        return (
            <div>
                { this.audios.map((audio, index) =>
                    <button onClick={() => this.toggle(audio) }>
                        PLAY AUDIO { index }
                    </button>
                ) }
            </div>
        )
    }
}


export default () => <AudioList list={[ audio1, audio2 ]} />;

PS:new Audio(url) 返回一个 HTMLAudioElement

【讨论】:

  • 我喜欢这个想法,但这会返回一个音频按钮列表,而不仅仅是一个。我认为你对new Audio(url) 返回一个 HTMLAudioElement 是正确的,但是如果我执行一个 document.getElementByTag('audio') 并安装其中的一些,我会返回一个空数组。我已经编辑了我的问题来代替。
【解决方案2】:

从马学正和 TheIncorrigible1 那里得到了一些重要的提示。基本上将音频移动到它自己的模块中。 playpause 方法从中导出,currentlyPlaying 在该模块中被跟踪。

我将Music 组件调整为如下所示

import React from 'react';
import playIcon from './images/play.png';
import pauseIcon from './images/pause.png';
import globalAudio from './globalAudio';

class Music extends React.Component {
    constructor(props) {
        super(props);
        this.state = { 'play': false };
        this.name = props.src;
        this.togglePlay = this.togglePlay.bind(this);
    }

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

    componentWillUnmount () {
        globalAudio.pause(this.name);
    }

    render() {
        return (
            <div style={this.props.style} className={this.props.className}>
                {this.state.play
                    ? <button className="audio-button" aria-label="Pause" onClick={this.togglePlay}><img src={pauseIcon} width="34" height="34" alt="Pause"></img></button>
                    : <button className="audio-button" aria-label="Play" onClick={this.togglePlay}><img src={playIcon} width="34" height="34" alt="Play"></img></button>}
            </div>
        );
    }
}

export default Music;

还有我的新模块globalAudio

import audio1 from './audio1.mp3';
import audio2 from './audio2.mp3';
import audio3 from './audio3.mp3';
import audio4 from './audio4.mp3';
import audio5 from './audio5.mp3';

const audios = {
    'audio1': new Audio(audio1),
    'audio2': new Audio(audio2),
    'audio3': new Audio(audio3),
    'audio4': new Audio(audio4),
    'audio5': new Audio(audio5)
};

let currentlyPlaying = null;

const play = (name) => {
    if (currentlyPlaying) {
        audios[currentlyPlaying].pause();
    }
    audios[name].play();
    currentlyPlaying = name;
};

const pause = (name) => {
    currentlyPlaying = null;
    audios[name].pause();
};

export default {
    pause,
    play
};

感谢所有建议,他们都非常有帮助。

【讨论】:

    【解决方案3】:

    创建一个模块来处理音频。向Music 公开播放、暂停、恢复等方法,并跟踪您拥有的所有五个Music 实例的不同音频。每当播放新音频时,都会暂停旧音频。

    【讨论】:

    • 你能给我一个例子来说明这个实现是什么样的吗?
    猜你喜欢
    • 1970-01-01
    • 2014-08-19
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多