【发布时间】:2018-12-22 14:30:03
【问题描述】:
我在 React 中制作了一个自定义音频播放器,它使用基于播放器持续时间的值更新音频文件(进度条)的所谓“Scrubber”。一切正常,除了如果您在间隔更新时按下播放/暂停按钮(mousedown -> 间隔更新状态 -> mouseup),那么按钮单击不会触发。
import React, { Component } from 'react';
import ReactSVG from 'react-svg';
import VolumeButton from 'components/VolumeButton/VolumeButton.jsx';
import play from 'img/icons/play.svg';
import pause from 'img/icons/pause.svg';
import './AudioPlayer.css';
class AudioPlayer extends Component {
constructor(props) {
super(props);
this.state = {
currentTime: '00:00',
endTime: '00:00',
intervalsInitiated: false,
player: null,
playing: false,
progressBar: null
};
this.handleResize = this.handleResize.bind(this);
}
initIntervals = () => {
let intervals = setInterval(() => {
this.updateScrubber(this.state.player.currentTime);
this.updateTime(this.state.player.currentTime);
}, 100);
this.setState({
intervals: intervals,
intervalsInitiated: true
});
};
setUpAudioTime = player => {
console.log('setup time');
let playerCurrentTime = player.currentTime;
let currentTime = this.calculateTime(playerCurrentTime);
this.setState({
currentTime: currentTime,
endTime: this.calculateTime(player.duration)
});
this.updateScrubber(playerCurrentTime);
};
initPlayer = () => {
console.log('initPlayer');
// Add resize listener for showing volume on desktop
this.addResize();
this.handleResize();
// Setup correct player
let player = new Audio(this.props.audioPath);
let progressBar = document.querySelector('.ProgressBar');
// Add event for audio stopped for play button
player.addEventListener('ended', () => this.toggleAudioPlay());
// Set state to correct player
// TODO: Do this in update aswell going from one to another
this.setState({
player: player,
progressBar: progressBar
});
player.addEventListener('loadedmetadata', () =>
this.setUpAudioTime(player)
);
};
toggleAudioPlay = () => {
console.log('toggling audio');
if (!this.state.player) {
return;
}
!this.state.intervalsInitiated
? this.initIntervals()
: this.resetComponent();
this.state.playing
? this.state.player.pause()
: this.state.player.play();
this.setState({
playing: !this.state.playing
});
};
updateScrubber = playerCurrentTime => {
if (!this.state.player || !this.state.progressBar) {
return;
}
let prog = this.state.progressBar;
prog.value = playerCurrentTime / this.state.player.duration;
this.setState({
progressBar: prog
});
};
updateTime = playerCurrentTime => {
this.setState({
currentTime: this.calculateTime(playerCurrentTime)
});
};
calculateTime = lengthInSeconds => {
let minutes = Math.floor(lengthInSeconds / 60);
let seconds = Math.floor(lengthInSeconds) - minutes * 60;
let time =
(minutes < 10 ? '0' + minutes : minutes) +
':' +
(seconds < 10 ? '0' + seconds : seconds);
return time;
};
seek = event => {
if (!this.state.player || !this.state.progressBar) {
return;
}
let percent =
event.nativeEvent.offsetX / this.state.progressBar.offsetWidth;
let prog = this.state.progressBar;
prog.value = percent;
this.setState({ progressBar: prog });
let newTime = percent * this.state.player.duration;
let player = this.state.player;
player.currentTime = newTime;
this.setState({
player: player
});
this.updateTime(newTime);
};
resetComponent() {
console.log('reset component');
clearInterval(this.state.intervals);
this.setState({
intervalsInitiated: false
});
}
componentDidMount() {
this.initPlayer();
}
render() {
return (
<div
className={`AudioPlayer ${
this.state.width < 800 ? 'AudioPlayer--extended' : ''
}`}
>
<audio className="MarkerAudio" preload="metadata">
<source src={this.props.audioPath} type="audio/mp3" />
Your device doesnt support audio format.
</audio>
<div className="PlayerControls">
<div className="PlayButton" onClick={this.toggleAudioPlay}>
{this.state.playing ? (
<ReactSVG
className="AudioIcon"
svgStyle={{ height: '100%', width: '100%' }}
path={pause}
/>
) : (
<ReactSVG
className="AudioIcon"
svgStyle={{
height: '100%',
left: '2px',
position: 'relative',
width: '100%'
}}
path={play}
/>
)}
</div>
<span className="CurrentTime">
{this.state.currentTime}
</span>
<progress
onClick={this.seek}
className="ProgressBar"
value="0"
min="0"
max="1"
/>
<span>{this.state.endTime}</span>
</div>
</div>
);
}
}
export default AudioPlayer;
但是,如果我确保执行“快速单击”或未启动间隔,则单击仍然有效。关于如何处理这个问题的任何想法?我应该使用 onMouseDown 还是其他东西?还是有什么办法确保间隔和状态的变化不会干扰 onClick?
【问题讨论】:
-
你能展示更多你的代码吗?我认为很难说当前问题中的代码有什么问题。
-
@Tholle 我真的不认为这是代码本身。更多的状态更新/onClick 事件,但我可以在更多部分进行编辑。给我一点时间。
-
不。它甚至没有记录它。或者更清楚一点 - 如果我在间隔更新之前单击(mousedown 和 mouseup),它会按预期工作。然后它会像预期的那样记录和更新。而且我越来越困惑,因为 seek 方法可以正常工作。感谢您抽出宝贵时间提供帮助。
-
例如,如果我将时间间隔更改为 10 秒,则点击会按我的意愿工作。但是,如果我单击并按住,等待 10 秒然后松开鼠标,则什么也没有发生。所以这肯定与更新间隔有关:D
-
哈哈哈@Tholle,既然你投入了这个,我终于想通了!我用于播放按钮的图标以某种方式冒泡,但是当状态更新时,冒泡以某种方式消失了。我简直不敢相信。现在一切都按预期工作。感谢您的宝贵时间。
标签: javascript reactjs onclick setinterval html5-audio