Управление несколькими источниками звука в React - PullRequest
0 голосов
/ 30 мая 2018

У меня есть компонент 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 или какую-либо другую библиотеку управления состоянием.Я бы хотел этого избежать, так как в остальном я не нуждаюсь в этом на этом сайте.Я посмотрел на слушателей событий (а именно, решение , предложенное здесь ), но когда я делаю document.getElementsByTagName('audio'), я получаю пустое HTMLCollection. Это решение ближе, но я не могу преодолеть разрыв между его реализацией в jQuery и той, которую я использую в React.

Есть ли способ идентифицировать воспроизводимый звук и приостановить его из компонента React перед воспроизведением нового звука?Любые и все предложения приветствуются.

Ответы [ 3 ]

0 голосов
/ 30 мая 2018
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 .

0 голосов
/ 30 мая 2018

Получил несколько важных советов от Сюэчжэна Ма и TheIncorrigible1.В основном переместил аудио в свой собственный модуль.Методы play и pause экспортируются из этого, а 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
};

Спасибо за все предложения,все они были очень полезны.

0 голосов
/ 30 мая 2018

Создать модуль для обработки аудио.Выставьте такие методы, как воспроизведение, пауза, возобновление и т. Д., На Music и отслеживайте различные аудиофайлы из всех пяти экземпляров Music, которые у вас есть.Всякий раз, когда воспроизводится новый звук, приостанавливается старый.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...