import React, { Component } from 'react'; import { Slider } from 'antd'; import './index.less'; import videojs from 'video.js'; import Assets from '@src/components/Assets'; import { generateUUID, formatSecondAuto } from '@src/services/Tools'; function fullScreen(id) { const element = document.getElementById(id); if (element.requestFullscreen) { element.requestFullscreen(); } else if (element.msRequestFullscreen) { element.msRequestFullscreen(); } else if (element.mozRequestFullScreen) { element.mozRequestFullScreen(); } else if (element.webkitRequestFullscreen) { element.webkitRequestFullscreen(); } } function exitFullscreen() { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } } let fullAgent = null; document.addEventListener('fullscreenchange', () => { if (fullAgent) fullAgent(); }); /* Firefox */ document.addEventListener('mozfullscreenchange', () => { if (fullAgent) fullAgent(); }); /* Chrome, Safari and Opera */ document.addEventListener('webkitfullscreenchange', () => { if (fullAgent) fullAgent(); }); /* IE / Edge */ document.addEventListener('msfullscreenchange', () => { if (fullAgent) fullAgent(); }); export default class Video extends Component { constructor(props) { super(props); this.ready = false; this.state = { id: generateUUID(8), playing: false, fulling: false, progress: 0, speed: 1 }; } componentDidMount() { this.player = videojs( this.videoNode, { controls: true, sources: [ { src: this.props.src, type: 'video/mp4', }, ], width: this.props.width, height: this.props.height, }, () => { this.ready = true; }, ); } componentWillUnmount() { if (this.player) { this.player.dispose(); } } clearTimeUpdate() { if (this.timeInterval) { clearInterval(this.timeInterval); this.timeInterval = null; } } refreshTimeUpdate() { if (this.timeInterval) { clearInterval(this.timeInterval); this.timeInterval = null; } this.timeInterval = setInterval(() => { const { onTimeUpdate } = this.props; if (onTimeUpdate) onTimeUpdate(this.player.currentTime()); this.setState({ progress: this.player.currentTime() * 100 / this.player.duration() }); }, 1000); } onChangeProgress(value) { if (!this.ready) return; this.player.currentTime((this.player.duration() * value) / 100); this.setState({ progress: (this.player.currentTime() * 100) / this.player.duration() }); const { onChangeProgress } = this.props; const { playing } = this.state; if (!playing) { this.player.pause(); } if (onChangeProgress) onChangeProgress(this.player.currentTime()); } onPlay() { if (!this.ready) return; const { onPlay } = this.props; this.player.play(); this.setState({ playing: true }); if (onPlay) onPlay(this.player.currentTime()); this.refreshTimeUpdate(); } onPause() { if (!this.ready) return; const { onPause } = this.props; this.player.pause(); this.setState({ playing: false }); if (onPause) onPause(this.player.currentTime()); this.clearTimeUpdate(); } onNext() { const { onNext } = this.props; this.player.pause(); this.clearTimeUpdate(); this.setState({ playing: false }); if (onNext) onNext(); } onSpeed(speed) { this.player.playbackRate(speed); this.setState({ selectSpeed: false, speed }); } selectSpeed(value) { this.setState({ selectSpeed: value }); } onFullChange() { this.setState({ fulling: !this.state.fulling }); if (this.props.onFullChange) this.props.onFullChange(); } onFull() { fullAgent = () => this.onFullChange(); fullScreen(this.state.id); } onExitFull() { exitFullscreen(); } showProgressTip(e) { let x = e.clientX; const percent = x * 100 / this.progress.clientWidth; const text = percent > 0 ? formatSecondAuto(percent * this.player.duration() / 100) : '00:00'; const width = text.length > 5 ? 67.8 : 47.3; x += 1; x -= width / 2; if (x < 0) { x = 0; } else if (x + width > this.progress.clientWidth) { x = this.progress.clientWidth - width; } this.setState({ pt: { left: x, display: 'block', text, width } }); } hideProgressTip() { this.setState({ pt: {} }); } render() { const { btnList = [], children, onAction, hideAction, water } = this.props; const { playing, fulling, id, selectSpeed, speed } = this.state; return ( <div id={id} className={`video-item ${!hideAction ? 'action' : ''} ${fulling ? 'full' : ''}`}> <div className="video-wrapper c-p" onClick={() => { return playing ? this.onPause() : this.onPlay(); }}> <video ref={node => { this.videoNode = node; }} // vjs-fluid /> {water} {!playing && <Assets className="play c-p" name="play" />} {playing && <Assets className="stop c-p" name="stop" />} </div> <div className="video-bottom"> {/* <div className="progress" /> */} {this.renderProgress()} {!hideAction && ( <div className="action-bar"> <div className="d-i-b m-r-1"> <Assets name={!playing ? 'play2' : 'stop2'} onClick={() => (playing ? this.onPause() : this.onPlay())} /> {/* {playing && <Assets name="stop2" onClick={() => this.onPause()} />} */} </div> <div className="d-i-b m-r-1"> <Assets name="next2" onClick={() => this.onNext()} /> </div> <div className="m-r-1 c-w">{this.ready ? (formatSecondAuto(this.player.currentTime())) : ('00:00')}</div> <div className="m-r-1 c-w">/</div> <div className="m-r-1 c-w">{this.ready ? (formatSecondAuto(this.player.duration())) : ('00:00')}</div> <div className="flex-block" /> {btnList.map(btn => { if (btn.full && !fulling) return ''; if (!btn.show) return ''; return ( <div className="d-i-b m-r-1"> {btn.render ? ( <div className="fix-btn-action d-i-b" onClick={() => { if (btn.pause) this.onPause(); if (onAction) onAction(btn.key); }} > {btn.render(btn.active)} </div> ) : (<div className={`btn-action ${btn.active ? 'active' : ''}`} onClick={() => onAction && onAction(btn.key)} >{btn.title}</div>)} </div> ); })} <div className="d-i-b m-r-1"> <div className={`btn-action ${selectSpeed ? 'active' : ''}`} onClick={() => this.selectSpeed(!selectSpeed)}> 倍速 </div> </div> <div className="d-i-b"> {!fulling && <Assets name="full2" onClick={() => this.onFull()} />} {fulling && <Assets name="reduction2" onClick={() => this.onExitFull()} />} </div> </div> )} </div> {selectSpeed && ( <div className="select-speed"> <div className={`item ${speed === 0.5 ? 'active' : ''}`} onClick={() => this.onSpeed(0.5)}> 0.5 </div> <div className={`item ${speed === 0.75 ? 'active' : ''}`} onClick={() => this.onSpeed(0.75)}> 0.75 </div> <div className={`item ${speed === 1 ? 'active' : ''}`} onClick={() => this.onSpeed(1)}> 正常 </div> <div className={`item ${speed === 1.25 ? 'active' : ''}`} onClick={() => this.onSpeed(1.25)}> 1.25 </div> <div className={`item ${speed === 1.5 ? 'active' : ''}`} onClick={() => this.onSpeed(1.5)}> 1.5 </div> <div className={`item ${speed === 2.0 ? 'active' : ''}`} onClick={() => this.onSpeed(2)}> 2.0 </div> </div> )} {children} </div> ); } renderProgress() { const { hideProgress } = this.props; const { progress, pt = {} } = this.state; return ( !hideProgress && ( <div ref={ref => { if (ref) this.progress = ref; }} onMouseMove={(e) => this.showProgressTip(e)} onMouseLeave={() => this.hideProgressTip()}><Slider value={progress || 0} step={0.01} tooltipVisible={false} onChange={value => this.onChangeProgress(value)} /><div className={'show-progress-tip'} style={{ ...pt }}>{pt.text}</div></div> ) ); } }