123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- 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>
- )
- );
- }
- }
|