题意:“React 音频播放器更改音频当前时间”
问题背景:
I'm working on a custom audio player in React with Bootstrap, and I want to make it possible to fast forward or rewind the playback by 5 seconds. I also want to be able to change the time using a slider. This somehow does not work. CURRENTLY the code behaves in such a way that if I fast forward or rewind 5 seconds the MP-3 starts again.
“我正在用 React 和 Bootstrap 开发一个自定义音频播放器,我想实现快进或倒退 5 秒的功能。我还希望能够使用滑块更改播放时间。但这似乎没有效果。目前的代码行为是,当我快进或倒退 5 秒时,MP3 会重新开始播放。”
App.js
import "bootstrap/dist/css/bootstrap.min.css";
import "./index.scss";
import { Button, Card, Container, ProgressBar } from "react-bootstrap";
import AudioPlayer from "./components/AudioPlayer";
export default function App() {
return (
<div className="App">
<Container>
<h1>Hello CodeSandbox</h1>
<Card>
<Card.Header> Audio </Card.Header>
<Card.Body>
<AudioPlayer
audioSrc="/assets/Test_ogg_mp3_48kbps.wav.ogg"
name="Lehrpfad Audio 1"
/>
</Card.Body>
</Card>
</Container>
</div>
);
}
AudioPlayer
import React from "react";
import { Button, ProgressBar, InputGroup, FormControl } from "react-bootstrap";
import {
PlayCircleFill,
PauseCircleFill,
VolumeMuteFill,
VolumeDownFill,
VolumeUpFill,
} from "react-bootstrap-icons";
class AudioPlayer extends React.Component {
constructor(props) {
super(props);
this.audioRef = React.createRef();
this.audioSrc = props.audioSrc;
this.state = {
isPlaying: false,
currentTime: 0,
volume: 1, // Range between 0 and 1
progress: 0,
};
}
togglePlayPause() {
const { isPlaying } = this.state;
const audio = this.audioRef.current;
if (isPlaying) {
audio.pause();
} else {
audio.play();
}
this.setState({ isPlaying: !isPlaying });
}
handleTimeUpdate() {
const audio = this.audioRef.current;
if (audio && !isNaN(audio.duration)) {
const progressPercentage = (audio.currentTime / audio.duration) * 100;
this.setState({ progress: progressPercentage });
if (progressPercentage >= 100) {
this.setState({ isPlaying: false, progress: 0 });
}
}
}
getVolumeIcon() {
const { volume } = this.state;
if (volume <= 0) {
return <VolumeMuteFill />;
} else if (volume > 0 && volume <= 0.5) {
return <VolumeDownFill />;
} else {
return <VolumeUpFill />;
}
}
handleVolumeChange(e) {
const newVolume = e.target.value;
this.setState({ volume: newVolume });
if (this.audioRef.current) {
this.audioRef.current.volume = newVolume;
}
}
skipTime(seconds) {
const player = document.getElementById("Player");
if (player && !isNaN(player.currentTime)) {
player.currentTime += seconds;
this.setState();
}
}
render() {
const { isPlaying, progress, volume } = this.state;
return (
<div className="container mt-5 audio-player">
<audio
id="Player"
ref={this.audioRef}
src={this.audioSrc} // Ersetze dies durch den Pfad zu deiner Audiodatei
onTimeUpdate={this.handleTimeUpdate.bind(this)}
onEnded={() => this.setState({ isPlaying: false })}
/>
<div className="d-flex align-items-center">
<Button variant="primary" onClick={() => this.skipTime(-5)}>
{" "}
-5s{" "}
</Button>
<Button
variant="primary"
onClick={this.togglePlayPause.bind(this)}
className="mx-2"
>
{isPlaying ? <PauseCircleFill /> : <PlayCircleFill />}
</Button>
<Button variant="primary" onClick={() => this.skipTime(5)}>
{" "}
+5s{" "}
</Button>
</div>
<ProgressBar
striped
variant="success"
now={progress}
label={`${Math.round(progress)}%`}
/>
<InputGroup className="mt-3">
<InputGroup.Text>{this.getVolumeIcon()}</InputGroup.Text>
<FormControl
type="range"
min="0"
max="1"
step="0.1"
value={volume}
onChange={this.handleVolumeChange.bind(this)}
/>
</InputGroup>
</div>
);
}
}
export default AudioPlayer;
I tried everything that came into my mind but i was not sucessfull. I did accept that a method would change the time.
“我尝试了所有能想到的方法,但都没有成功。我接受了一个方法来改变播放时间。”
codesandbox.io snippet
问题解决:
import React from "react";
import { Button, ProgressBar, InputGroup, FormControl } from "react-bootstrap";
import {
PlayCircleFill,
PauseCircleFill,
VolumeMuteFill,
VolumeDownFill,
VolumeUpFill,
ArrowClockwise,
ArrowCounterclockwise,
} from "react-bootstrap-icons";
class AudioPlayer extends React.Component {
constructor(props) {
super(props);
this.audioRef = React.createRef();
this.audioSrc = props.audioSrc;
this.audioName = props.audioName || props.audioSrc;
this.state = {
isPlaying: false,
currentTime: 0,
volume: 1, // Range between 0 and 1
progress: 0,
};
}
togglePlayPause() {
const { isPlaying } = this.state;
const audio = this.audioRef.current;
if (isPlaying) {
audio.pause();
} else {
audio.play();
}
this.setState({ isPlaying: !isPlaying });
}
handleTimeUpdate() {
const audio = this.audioRef.current;
if (audio && !isNaN(audio.duration)) {
const progressPercentage = (audio.currentTime / audio.duration) * 100;
this.setState({ progress: progressPercentage });
if (progressPercentage >= 100) {
this.setState({ isPlaying: false, progress: 0 });
}
}
}
getVolumeIcon() {
const { volume } = this.state;
if (volume <= 0) {
return <VolumeMuteFill />;
} else if (volume > 0 && volume <= 0.5) {
return <VolumeDownFill />;
} else {
return <VolumeUpFill />;
}
}
handleVolumeChange(e) {
const newVolume = e.target.value;
this.setState({ volume: newVolume });
if (this.audioRef.current) {
this.audioRef.current.volume = newVolume;
}
}
skipTime(seconds) {
const audio = this.audioRef.current;
if (audio && !isNaN(audio.currentTime)) {
audio.currentTime += seconds;
}
}
render() {
const { isPlaying, progress, volume } = this.state;
return (
<div className="audio-player">
<p>{this.audioName}</p>
<audio
id="Player"
ref={this.audioRef}
src={this.audioSrc} // Ersetze dies durch den Pfad zu deiner Audiodatei
onTimeUpdate={this.handleTimeUpdate.bind(this)}
onEnded={() => this.setState({ isPlaying: false })}
controls
/>
<Button
variant={isPlaying ? "danger" : "success"}
onClick={this.togglePlayPause.bind(this)}
className="playPauseBtn"
>
{isPlaying ? (
<PauseCircleFill size={80} />
) : (
<PlayCircleFill size={80} />
)}
</Button>
<div className="audio-controls">
<Button variant="primary" onClick={() => this.skipTime(-5)}>
<ArrowCounterclockwise size={50} />
-5sec
</Button>
<Button variant="primary" onClick={() => this.skipTime(5)}>
<ArrowClockwise size={50} />
+5sec
</Button>
</div>
<ProgressBar
striped
variant="success"
now={progress}
label={`${Math.round(progress)}%`}
/>
<InputGroup className="volume-input">
<InputGroup.Text>{this.getVolumeIcon()}</InputGroup.Text>
<FormControl
type="range"
min="0"
max="1"
step="0.1"
value={volume}
onChange={this.handleVolumeChange.bind(this)}
/>
</InputGroup>
</div>
);
}
}
export default AudioPlayer;