我想在网站上创建一个音乐播放器。想法是选择一首歌曲并自动播放。这首歌必须在所有页面上播放,我需要一个播放/暂停按钮。 我已经创建了所有组件,但有一个错误。当我在带有播放器组件的主页上时,播放/暂停按钮无法正常工作,如果我停止音乐,我无法再次启动它,它只能在其他页面上使用。这是网站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;
谢谢! :)
我认为问题出在这里:
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;
主要问题似乎是处理播放/暂停功能以及跨不同组件同步音乐播放器的状态。
解决方案: