我有一个React.js组件,它是一个audio
文件和一个子组件,其中是一个带有播放/暂停按钮的滑块。我希望滑块中的箭头位置与音频当前时间同步。
播放音频时,箭头动画会延迟,有时会更多,有时会更少。当音频暂停时,箭头动画立即发生。当音频播放没有延迟时,如何才能达到同样的效果?
class Player extends React.Component {
constructor(props) {
super(props);
this.state = {
};
this.playClick = this.playClick.bind(this);
this.changePosition = this.changePosition.bind(this);
}
componentWillReceiveProps(nextProps) {
const that = this;
if (this.props.currentTime !== nextProps.currentTime) {
const horizontalOffset = nextProps.currentTime * 500 / this.props.duration;
console.log('horOffset', horizontalOffset);
$('.arrow').animate(
{ left: `${horizontalOffset - 20}px` },
{
duration: 'slow',
easing: 'easeInOutExpo',
},
);
}
}
changePosition(e){
const newCurrTime = this.props.duration * e.clientX / 500;
console.log('changed time', newCurrTime);
this.props.onChangeAudioTime(newCurrTime);
}
playClick() {
this.props.onTogglePlay();
}
render() {
return <div>
<button onClick={this.playClick}>play</button>
<div className="slider-content" onClick={this.changePosition}>
<div className="arrow">
</div>
</div>
</div>;
}
}
class Audio extends React.Component {
constructor(props) {
super(props);
this.state = {
play: false,
current: 0,
duration: 2024.496,
seeked: false
};
this.toggle = this.toggle.bind(this);
this.play = this.play.bind(this);
this.pause = this.pause.bind(this);
this.setCurrTime = this.setCurrTime.bind(this);
}
componentDidMount() {
const that = this;
this.currentTimeInterval = null;
this.audio.onplay = () => {
this.currentTimeInterval = setInterval(() => {
if (that.state.current !== this.audio.currentTime) {
that.setState({ current: this.audio.currentTime, seeked: false });
}
}, 500);
};
this.audio.onseeked = () => {
this.currentTimeInterval = setInterval(() => {
if (that.state.current !== this.audio.currentTime) {
that.setState({ current: this.audio.currentTime, seeked: false });
}
}, 500);
};
this.audio.onpause = () => {
clearInterval(this.currentTimeInterval);
};
}
play() {
this.setState({ play: true }, () => {
this.audio.play();
});
}
pause() {
this.setState({ play: false }, () => {
this.audio.pause();
});
}
toggle() {
this.state.play ? this.pause() : this.play();
}
setCurrTime(newCurrTime) {
let that = this;
clearInterval(this.currentTimeInterval);
this.setState({ current: newCurrTime, seeked: true }, () => {
this.audio.currentTime = newCurrTime;
});
}
render() {
return <div>
<audio src="https://dts.podtrac.com/redirect.mp3/www.kqed.org/.stream/mp3splice/radio/theleap/2017/04/HennyMastered.mp3"
id="audio"
ref={el => (this.audio = el)}
/>
<Player
currentTime={this.state.current}
duration={this.state.duration}
onTogglePlay={this.toggle}
onChangeAudioTime={this.setCurrTime}
play={this.state.play}
ref={el => (this.player = el)}
/>
</div>;
}
}
ReactDOM.render(
<Audio name="World" />,
document.getElementById('container')
);
答案 0 :(得分:2)
我的猜测是因为$.animate
在新动画开始时没有完成。根据{{3}} slow
动画的持续时间为600毫秒。
将jQuery和反应结合起来并不是一个好习惯。因此,我建议您使用jQuery docs来实现所需的行为。
示例强>
// in css file
div.arrow {
left: 0; /* desired initial left value */
transition: left 500ms;
-moz-transition: left 500ms;
-webkit-transition: left 500ms;
-o-transition: left 500ms;
}
// in component class
componentWillReceiveProps(nextProps) {
const that = this;
if (this.props.currentTime !== nextProps.currentTime) {
const horizontalOffset = nextProps.currentTime * 500 / this.props.duration;
console.log('horOffset', horizontalOffset);
this.setState({ leftValue: (horizontalOffset - 20) });
}
}
render() {
return (
<div>
<button onClick={this.playClick}>play</button>
<div className="slider-content" onClick={this.changePosition}>
<div className="arrow" style={{left: this.state.leftValue}}></div>
</div>
</div>
);
}