反应音乐播放器

问题描述 投票:0回答:2

我想在网站上创建一个音乐播放器。想法是选择一首歌曲并自动播放。这首歌必须在所有页面上播放,我需要一个播放/暂停按钮。 我已经创建了所有组件,但有一个错误。当我在带有播放器组件的主页上时,播放/暂停按钮无法正常工作,如果我停止音乐,我无法再次启动它,它只能在其他页面上使用。这是网站https://thebrandbar.studio/#/

应用程序.js

import React, { useState } from 'react';
import { HashRouter as Router, Route, Switch } from "react-router-dom";
import ScrollToTop from "./helper/scrollToTop";

import Home from "./pages/Home";
import Projects from "./pages/Projects";
import Team from "./pages/Team";
import ProjectPage from "./pages/ProjectPage";
import Error from "./pages/Error";
import TermsOfUse from "./pages/TermsOfUse";
import PrivacyPolicy from "./pages/PrivacyPolicy";
import Cookies from "./pages/Cookies";


const App = () => {
    const [currentTrackIndex, setCurrentTrackIndex] = useState(null);
    const [trackURL, setTrackURL] = useState('');
    const [playing, setPlaying] = useState(false);

    const callbackFunction = (currentTrackIndex, trackURL, playing) => {
        setCurrentTrackIndex(currentTrackIndex);
        setTrackURL(trackURL);
        setPlaying(playing);
    };

    const player = document.getElementById('player');
    const onPlayPauseClickHandler = (event) => {
        setPlaying(!playing);
        if (!playing) {
            player.play();
        } else {
            player.pause();
        }
    }
    const renderPlayBtn = () => {
        if (currentTrackIndex == null) {
            return;
        } else {
            return <div className="play-btn">
                <p onClick={onPlayPauseClickHandler} className={`play ${playing ? "red-bg" : "blue-bg"}`}>
                    {playing ? "SOUND OFF" : "SOUND ON"}
                </p>
            </div>
        }
    }

    return (
        <>
            <Router>
                <ScrollToTop />
                <Switch>
                    <Route exact path={`${process.env.PUBLIC_URL + '/'}`} >
                        <Home parentCallback={callbackFunction} player={player}/>
                    </Route>
                    <Route
                        path={`${process.env.PUBLIC_URL + '/projects'}`}
                        component={Projects}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL}/project/:projectId`}
                        component={ProjectPage}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/team'}`}
                        component={Team}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/terms'}`}
                        component={TermsOfUse}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/privacy'}`}
                        component={PrivacyPolicy}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/cookies'}`}
                        component={Cookies}
                    />
                    <Route exact component={Error} />
                </Switch>
            </Router>
            <audio id="player" src={trackURL} type="audio/mpeg"></audio>
            {
                renderPlayBtn()
            }
        </>
    );
};

export default App;

主页

import React, { useState, useEffect } from 'react';
import Loader from "../container/Loader";
import { Helmet } from "react-helmet";
import Cookies from "../components/cookies";
import LayoutDefault from "../container/LayoutDefault";
import Header from "../components/header/Header";
import HeroArea from "../container/Hero";
import MusicPlayer from "../container/MusicPlayer";
import FeaturedProjects from "../container/FeaturedProjects";
import Contact from "../container/Contact";
import Footer from "../container/Footer";

const Home = ({ parentCallback, player }) => {
    const [currentTrackIndex, setCurrentTrackIndex] = useState(null);
    const [trackURL, setTrackURL] = useState('');
    const [playing, setPlaying] = useState(false);

    const callbackFunction = (currentTrackIndex, trackURL, playing) => {
        setCurrentTrackIndex(currentTrackIndex);
        setTrackURL(trackURL);
        setPlaying(playing);
    };

    useEffect(() => {
        parentCallback(currentTrackIndex, trackURL, playing);
    });


    return (
        <Loader>
            <Helmet>
                <title>TheBrandBar</title>
            </Helmet>
            <Cookies />
            <LayoutDefault className="template-color-2 bg_color--4">
                <Header />
                <HeroArea />
                <MusicPlayer parentCallback={callbackFunction} player={player}/>
                <FeaturedProjects />
                <Contact />
                <Footer />
            </LayoutDefault>
        </Loader>
    );
};

export default Home;

和音乐播放器组件

import React, { useState, useEffect } from "react";
import { Container, Row, Col } from "react-bootstrap";

import DB from '../data/music/music.js';


const Player = ({ parentCallback }) => {

  const [tracksList] = useState(DB);
  const [currentTrackIndex, setCurrentTrackIndex] = useState(null);
  const [trackID, setTrackID] = useState(null);
  const [trackURL, setTrackURL] = useState('');
  const [playing, setPlaying] = useState(false);

  useEffect(() => {
    parentCallback(currentTrackIndex, trackURL, playing);
  });

  const selectThisTrack = (event, trackID) => {
    let currentTrackIndex = 0;
    tracksList.map((track, index) => {
      if (track.id === trackID) {
        currentTrackIndex = index;
      }
      return track;
    });
    setCurrentTrackIndex(currentTrackIndex);
    setTrackID(tracksList[currentTrackIndex].id);
    setTrackURL(require(`../assets/player/music/${currentTrackIndex + 1}.mp3`));
    setPlaying(true);
    const player = document.getElementById('player');
    player.src = trackURL;
    player.preload = true;
    player.autoplay = true;
    player.loop = true;
    if (playing) {
      player.play();
    } else {
      player.pause();
    }
  }
  

  const renderCover = () => {
    if (!playing) {
      return <img className="img-cover-default" src={require(`../assets/player/covers/default.gif`)} alt="" />
    } else {
      return <img className="img-cover" src={require(`../assets/player/covers/${currentTrackIndex + 1}.gif`)} alt="" />
    }
  }


  return (
    <>
      <Container>
        <Row>
          <Col className="play-list" xs={{ span: 12, order: 2 }} lg={{ span: 4, order: 1 }}>
            <p className="your-rythm ">WHAT'S YOUR RYTHM?</p>
            <br />
            {DB.map((track, index) => (
              <div
                key={track.id}
                index={index}
                className={`song ${track.id === trackID ? "selected" : ""}`}
                id={track.id === trackID ? "activeTrack" : ""}
                onClick={(ev) => selectThisTrack(ev, track.id)}
              >
                <p>{track.title}</p>
              </div>
            ))}
          </Col>
          <Col xs={{ span: 12, order: 1 }} lg={{ span: 8, order: 2 }}>

            <div className="song-cover">
              {
                renderCover()
              }
            </div>

          </Col>
        </Row>
      </Container>

    </>
  );
};

export default Player;

谢谢! :)

javascript html reactjs react-native react-hooks
2个回答
0
投票

我认为问题出在这里:

const player = document.getElementById('player');
    const onPlayPauseClickHandler = (event) => {
        setPlaying(!playing);
        if (!playing) {
            player.play();
        } else {
            player.pause();
        }
    }

React 在调用

set*
后不会立即更新。相反,您必须使用
useEffect
来播放/暂停。

删除

if (!playing) {
    player.play();
} else {
    player.pause();
}

并在

useEffect
中使用它。

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

编辑

useEffect
放在这里:

const App = () => {
    const [currentTrackIndex, setCurrentTrackIndex] = useState(null);
    const [trackURL, setTrackURL] = useState('');
    const [playing, setPlaying] = useState(false);

    const callbackFunction = (currentTrackIndex, trackURL, playing) => {
        setCurrentTrackIndex(currentTrackIndex);
        setTrackURL(trackURL);
        setPlaying(playing);
    };

    const player = document.getElementById('player');
    const onPlayPauseClickHandler = (event) => {
        setPlaying(!playing);
    }
    const renderPlayBtn = () => {
        if (currentTrackIndex == null) {
            return;
        } else {
            return <div className="play-btn">
                <p onClick={onPlayPauseClickHandler} className={`play ${playing ? "red-bg" : "blue-bg"}`}>
                    {playing ? "SOUND OFF" : "SOUND ON"}
                </p>
            </div>
        }
    }

    // PLACE IT HERE
    useEffect(() => {
        !playing ? player.play() : player.pause();
    }, [playing]);

    return (
        <>
            <Router>
                <ScrollToTop />
                <Switch>
                    <Route exact path={`${process.env.PUBLIC_URL + '/'}`} >
                        <Home parentCallback={callbackFunction} player={player}/>
                    </Route>
                    <Route
                        path={`${process.env.PUBLIC_URL + '/projects'}`}
                        component={Projects}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL}/project/:projectId`}
                        component={ProjectPage}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/team'}`}
                        component={Team}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/terms'}`}
                        component={TermsOfUse}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/privacy'}`}
                        component={PrivacyPolicy}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/cookies'}`}
                        component={Cookies}
                    />
                    <Route exact component={Error} />
                </Switch>
            </Router>
            <audio id="player" src={trackURL} type="audio/mpeg"></audio>
            {
                renderPlayBtn()
            }
        </>
    );
};

export default App;

0
投票

主要问题似乎是处理播放/暂停功能以及跨不同组件同步音乐播放器的状态。

  1. 确保玩家引用在组件之间正确传递和更新。
  2. 避免直接操作 DOM 元素(如 document.getElementById)并使用 React refs 以便更好地与 React 生命周期集成。
  3. 以更 React 友好的方式更新玩家状态。

解决方案:

  1. 移除player道具并依赖回调函数。
  2. 为音频播放器使用 React ref,并更稳健地处理播放/暂停。
  3. 确保正确调用parentCallback并处理曲目选择。
© www.soinside.com 2019 - 2024. All rights reserved.