赞
踩
多个视频要用同一个进度条控制播放暂停
这个可以用antd的Slider组件
<Slider
marks={marks}
max={maxTime}
defaultValue={timeValue}
value={timeValue}
tooltipVisible={false}
onAfterChange={(v) => handleAfterChange(v)}
onChange={(value) => handleSliderValue(value)}
/>
<video
id={!nickname ? '' : `play${id}`}
muted="muted"
className="video-js vjs-fluid"
// controls
preload="auto"
// poster="//vjs.zencdn.net/v/oceans.png"
data-setup="{}"
>
<source src={mediaUrl} type={sourceType} />
</video>
// 初始化videoJs const handleInitVideo = () => { // debugger // console.log({masterList}) videoList.map(v => { const {id, nickname } = v // console.log(document.getElementById(`play${id}`)) if (document.getElementById(`play${id}`) && !current[`play${id}`] && nickname) { current[`play${id}`] = videoJs(`play${id}`, { fluid: true }, function() { console.log(`1111play${id}`); // current[`play${id}`].play(); }); current[`play${id}`].src([{src:v.mediaUrl, type:v.sourceType}]) } return // } }) }
// 遍历每个video const handleEveryVideo = (list, fun, time) => { for (let i in list) { if (i !== 'timer' && list[i]) { // console.log('list[i]', fun,i, list[i]) switch (fun) { case 'play': // 播放 list[i].play(); break; case 'pause': // 暂停 list[i].pause(); break; // 设置时间点 case 'currentTime': list[i].currentTime(time); break; case 'dispose': // 销毁 list[i].dispose(); break; default: break; } } } }
import React, { useEffect, useRef, useState, forwardRef, useImperativeHandle } from 'react'; import Slider from 'react-slick'; import videoJs from 'video.js'; // import moment from 'moment'; import { Slider as Sli } from 'antd'; import 'slick-carousel/slick/slick.css'; import 'slick-carousel/slick/slick-theme.css'; import arr from '../../images/arr-right.svg'; import qh from '../../images/qh.svg'; import play from '../../images/play.svg'; import pause from '../../images/pause.svg'; import kj from '../../images/kj.svg'; import kt from '../../images/kt.svg'; // import CandidateVideo from './candidateVideo'; import './index.scss'; // const startTime = 1581926464; // const endTime = 1582926501; // const maxTime = endTime - startTime; // const maxTime = 46000; const VideoLeft = forwardRef(({videoList = [], masterList=[], currentVideoInfo, setCurrentVideoInfo, handleChangeCandidateVideo, setCurrentMasterInfo, currentMasteroInfo, handleChangeMasterVideo, formatDuring, timeValue,setTimeValue, current, setIsPlay, isPlay, maxTime }, ref) => { // const [ isPlay, setIsPlay ] = useState(false); const [ slideList, setSlideList ] = useState([]); const slideRef = useRef(); // let { current } = useRef({ timer: '' }); // let masterVideo = useRef(''); // let videojs = useRef(''); const marks = { 0: formatDuring(timeValue) // maxTime: formatDuring(maxTime), }; marks[maxTime] = formatDuring(maxTime); const handleSlideList = info => { const slideList = videoList.filter(i => i.id !== info.id) // console.log({slideList}) setSlideList(slideList) return 'ok' } // useEffect(() => { // if (allVideoList.length && allVideoList[0].startTime) handleObtainTime() // }, [allVideoList]) useEffect(() => { // console.log('slideList1') if(videoList.length) handleSlideList(currentVideoInfo) },[videoList, currentVideoInfo]) // 遍历每个video const handleEveryVideo = (list, fun, time) => { for (let i in list) { if (i !== 'timer' && list[i]) { // console.log('list[i]', fun,i, list[i]) switch (fun) { case 'play': // 播放 list[i].play(); break; case 'pause': // 暂停 list[i].pause(); break; // 设置时间点 case 'currentTime': list[i].currentTime(time); break; case 'dispose': // 销毁 list[i].dispose(); break; default: break; } } } } // 可以让父组件调用子组件的方法 useImperativeHandle(ref, () => ({ // 点击左右切换候视频 hanldeChangeListVideo (video, list, index, type) { // console.log({type}) let v = JSON.parse(JSON.stringify(video)); // if (index > -1) { setIsPlay(false); // console.log('index', list, currentVideoInfo) if (type === '1') { // 候选人 current[`play${list[index].id}`].src([{src:currentVideoInfo.mediaUrl, type:currentVideoInfo.sourceType}]) // 设置当前选择的候选人src current[`play${currentVideoInfo.id}`].src([{src:v.mediaUrl, type:v.sourceType}]) // 设置大框的候选人src list[index].nickname = currentVideoInfo.nickname list[index].mediaUrl = currentVideoInfo.mediaUrl list[index].sourceType = currentVideoInfo.sourceType setCurrentVideoInfo({id:currentVideoInfo.id,nickname:v.nickname, mediaUrl:v.mediaUrl,sourceType:v.sourceType}) } else { // 面试官 // current[`play${list[index].id}`].src([{src:currentMasteroInfo.mediaUrl, type:currentMasteroInfo.sourceType}]) // 设置当前选择的面试官src current[`play${currentMasteroInfo.id}`].src([{src:v.mediaUrl, type:v.sourceType}]) // 设置大框的面试官src // list[index].nickname = currentMasteroInfo.nickname // list[index].mediaUrl = currentMasteroInfo.mediaUrl // list[index].sourceType = currentMasteroInfo.sourceType setCurrentMasterInfo({id:currentMasteroInfo.id,nickname:v.nickname, mediaUrl:v.mediaUrl,sourceType:v.sourceType}) } const second = parseInt(timeValue / 1000); // handleInitVideo() handleEveryVideo(current, 'currentTime', second);// 给视频指定播放时间点 // console.log('slideList',slideList) // } // setIsPlay(true); } })); // 点击切换候选人视频 const hanldeChangeVideo = async video => { // handleEveryVideo(current, 'dispose');// 给视频指定播放时间点 let v = JSON.parse(JSON.stringify(video)); // let c = JSON.parse(JSON.stringify(currentVideoInfo)); const index = videoList.map(item => item.id).indexOf(video.id) if (index > -1) { // videoList[index] = currentVideoInfo setIsPlay(false); // setSlideList([...videoList]) current[`play${videoList[index].id}`].src([{src:currentVideoInfo.mediaUrl, type:currentVideoInfo.sourceType}]) // 设置当前选择的候选人src current[`play${currentVideoInfo.id}`].src([{src:v.mediaUrl, type:v.sourceType}]) // 设置大框的候选人src videoList[index].nickname = currentVideoInfo.nickname videoList[index].mediaUrl = currentVideoInfo.mediaUrl videoList[index].sourceType = currentVideoInfo.sourceType // console.log('index', v, video, videoList[index], c,currentVideoInfo) setCurrentVideoInfo({id:currentVideoInfo.id,nickname:v.nickname, mediaUrl:v.mediaUrl,sourceType:v.sourceType}) const second = parseInt(timeValue / 1000); // handleInitVideo() handleEveryVideo(current, 'currentTime', second);// 给视频指定播放时间点 // console.log('slideList',slideList) } // setIsPlay(true); } // 点击滑块到某个点之后 const handleAfterChange = (v) => { // console.log({v}); // clearInterval(timer); setTimeValue(v); const second = parseInt(v / 1000); // current.videojs.currentTime(second); // 给视频指定播放时间点 // current.masterVideo.currentTime(second); handleEveryVideo(current, 'currentTime', second); // console.log({current}) }; // 滑块的变化 const handleSliderValue = (v) => { // clearInterval(timer); setTimeValue(v); }; // const time = formatDuring(maxTime) // console.log({time}); // 开始暂停 const handlePlay = () => { setIsPlay(!isPlay); }; // 快进10秒 const handleFastForward = () => { timeValue = timeValue + 10000; if (timeValue <= maxTime) { setTimeValue(timeValue); const second = parseInt(timeValue / 1000); // current.videojs.currentTime(second); // 给视频指定播放时间点 // current.masterVideo.currentTime(second); // 给视频指定播放时间点 handleEveryVideo(current, 'currentTime', second); } else { setTimeValue(maxTime); const second = parseInt(maxTime / 1000); handleEveryVideo(current, 'currentTime', second); // current.videojs.currentTime(second); // 给视频指定播放时间点 // current.masterVideo.currentTime(second); // 给视频指定播放时间点 } }; // 快退10秒 const handleFastBack = () => { timeValue = timeValue - 10000; if (timeValue > 0) { setTimeValue(timeValue); const second = parseInt(timeValue / 1000); handleEveryVideo(current, 'currentTime', second); // current.videojs.currentTime(second); // 给视频指定播放时间点 // current.masterVideo.currentTime(second); // 给视频指定播放时间点 } else { setTimeValue(0); handleEveryVideo(current, 'currentTime', 0); // current.videojs.currentTime(0); // 给视频指定播放时间点 // current.masterVideo.currentTime(0); // 给视频指定播放时间点 } // setTimeValue(timeValue); }; // 初始化videoJs const handleInitVideo = () => { // debugger // console.log({masterList}) videoList.map(v => { const {id, nickname } = v // console.log(document.getElementById(`play${id}`)) if (document.getElementById(`play${id}`) && !current[`play${id}`] && nickname) { current[`play${id}`] = videoJs(`play${id}`, { fluid: true }, function() { console.log(`1111play${id}`); // current[`play${id}`].play(); }); current[`play${id}`].src([{src:v.mediaUrl, type:v.sourceType}]) } return // } }) } // 初始化面试官videoJs const handleInitMasterVideo = () => { // debugger // console.log({masterList}) masterList.map(v => { const {id, nickname } = v // console.log(document.getElementById(`play${id}`)) if (document.getElementById(`play${id}`) && !current[`play${id}`] && nickname) { current[`play${id}`] = videoJs(`play${id}`, { fluid: true }, function() { console.log(`222play${id}`); // current[`play${id}`].play(); }); current[`play${id}`].src([{src:v.mediaUrl, type:v.sourceType}]) } return // } }) } useEffect( () => { clearInterval(current.timer); // console.log({isPlay}); if (isPlay) { current.timer = setInterval(() => { timeValue = timeValue + 1000; setTimeValue(timeValue); if (timeValue >= maxTime) { setTimeValue(maxTime); clearInterval(current.timer); setIsPlay(false); } }, 1000); } }, [ current.timer, timeValue, isPlay ] ); useEffect( () => { // if (document.getElementById(`play${currentMasteroInfo.id}`) && document.getElementById(`play${currentVideoInfo.id}`)) { current[`play${currentMasteroInfo.id}`] = videoJs(`play${currentMasteroInfo.id}`, { fluid: true }, function() { console.log('Good to go1!'); // player.play(); if (masterList.length) handleInitMasterVideo() }); current[`play${currentVideoInfo.id}`] = videoJs(`play${currentVideoInfo.id}`, { fluid: true }, function() { console.log('Good to go!'); // player.play(); if (videoList.length) handleInitVideo() }); // console.log({videoList}) // handleInitVideo() if (isPlay) { handleEveryVideo(current, 'play'); } else { handleEveryVideo(current, 'pause'); } // current.videojs.on('play', function() { // console.log('开始/恢复播放'); // }); // current.videojs.on('ended', function() { // console.log('结束播放'); // }); // current.videojs.on('timeupdate', function() { // console.log('timeupdate'); // }); // } }, [ isPlay, current, videoList, masterList] ); const settings = { // focusOnSelect: true, infinite: true, slidesToShow: 3, slidesToScroll: 3, speed: 500 // nextArrow:<Right />, // prevArrow:<Right />, }; // console.log({current,slideList, videoList}) return ( <div className="video-container"> <h4>面试回放</h4> <div className="video-master candidate-video"> <div className="label-top"> <span className="video-label master">面试官</span> <span className="video-time">{formatDuring(timeValue)}</span> </div> <div className="label-middle vertical-middle"> <video id={`play${currentMasteroInfo.id}`} muted="muted" className="video-js vjs-fluid" width='320px' height='180px' // controls preload="auto" // poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}" > <source src={currentMasteroInfo.mediaUrl} type={currentMasteroInfo.sourceType} /> </video> </div> <div className="label-bottom"> <span className="label-arrow" onClick={() => handleChangeMasterVideo('left')}> <img className="rotate180" src={qh} alt="" /> </span> <span className="master-name">{currentMasteroInfo.nickname}</span> <span className="label-arrow" onClick={() => handleChangeMasterVideo('right')}> <img className="" src={qh} alt="" /> </span> </div> </div> <div className="video-master candidate-video"> <div className="label-top"> <span className="video-label candidate">候选人</span> <span className="video-time">{formatDuring(timeValue)}</span> </div> <div className="label-middle vertical-middle"> <video id={`play${currentVideoInfo.id}`} muted="muted" className="video-js vjs-fluid" // controls preload="auto" // poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}" > <source src={currentVideoInfo.mediaUrl} type={currentVideoInfo.sourceType} /> </video> </div> <div className="label-bottom"> <span className="label-arrow" onClick={() => handleChangeCandidateVideo('left')}> <img className="rotate180" src={qh} alt="" /> </span> <span className="master-name">{currentVideoInfo.nickname}</span> <span className="label-arrow" onClick={() => handleChangeCandidateVideo('right')}> <img className="" src={qh} alt="" /> </span> </div> </div> { slideList.length > 3 ? <div className="candidate-bottom-slider"> <img src={arr} alt="" className="left-arr rotate180" onClick={() => slideRef.current.slickPrev()} /> <div className="candidate-slide"> <Slider ref={slideRef} {...settings}> {slideList.map((video) => { const { id, nickname, mediaUrl, sourceType } = video; return ( // <CandidateVideo key={video.id} video={video} current={current} isPlay={isPlay} /> <div className={`${!nickname ? 'hide' : 'video-item '}`} key={id} onClick={() => hanldeChangeVideo(video)}> {/* <div className={`video-middle ${isLong ? 'video-vertical' : ''}`}> */} <div className="video-middle"> <video id={!nickname ? '' : `play${id}`} muted="muted" className="video-js vjs-fluid" // controls preload="auto" // poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}" > <source src={mediaUrl} type={sourceType} /> </video> </div> <span className="candidate-name">{nickname}</span> </div> ); })} </Slider> </div> <img src={arr} alt="" className="left-arr" onClick={() => slideRef.current.slickNext()} /> </div> : <div className="candidate-bottom-slider"> <div className="candidate-slide slide-three"> {slideList.map((video) => { const { id, nickname, mediaUrl, sourceType } = video; return ( // <CandidateVideo key={video.id} video={video} current={current} isPlay={isPlay} /> <div className={`${!nickname ? 'hide' : 'video-item '}`}key={id} onClick={() => hanldeChangeVideo(video)}> {/* <div className={`video-middle ${isLong ? 'video-vertical' : ''}`}> */} <div className="video-middle"> <video id={`play${id}`} muted="muted" className="video-js vjs-fluid" // controls preload="auto" // poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}" > <source src={mediaUrl} type={sourceType} /> </video> </div> <span className="candidate-name">{nickname}</span> </div> ); })} </div> </div> } <div className="slider-line"> <Sli marks={marks} max={maxTime} defaultValue={timeValue} value={timeValue} tooltipVisible={false} onAfterChange={(v) => handleAfterChange(v)} onChange={(value) => handleSliderValue(value)} /> </div> <div className="play-pause"> <span onClick={() => handleFastBack()}> <img src={kt} alt="" /> </span> <span onClick={() => handlePlay()}> <img src={isPlay ? play : pause} alt="" /> </span> <span onClick={() => handleFastForward()}> <img src={kj} alt="" /> </span> </div> </div> ); }); export default VideoLeft;
import React, { useState, useEffect, useRef } from 'react'; import { message } from 'antd'; import './index.scss'; import VideoLeft from '../components/videoLeft'; // 获取url参数,调用方式:getQueryVariable('xxx') const getQueryVariable = (variable) => { var query = window.location.search.substring(1); var vars = query.split("&"); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); if (pair[0] == variable) { return pair[1]; } } return false; }; // 先查会议里面人的信息 const meetingInfo = { token: '111', userId: 'c_G111', roomId: 3009, startTime: '2021-02-04 16:38:00', endTime: '2021-02-04 17:38:00', userList: [ { id: 'c_G12', phone: '13222222222', nickname: 'Alice', roomId: '2482', mediaUrl:'https://vjs.zencdn.net/v/oceans.mp4', startTime:1612495748, endTime:1612550188, sourceType:'video/mp4' }, { id: 'c_G13', phone: '13222222223', nickname: 'Jane', roomId: '2482', mediaUrl:'https://vjs.zencdn.net/v/oceans.mp4', startTime:1612495748, endTime:1612550188, sourceType:'video/mp4' }, { id: 'c_G14', phone: '13222222224', nickname: 'Jack', roomId: '2482', mediaUrl:'https://vjs.zencdn.net/v/oceans.mp4', startTime:1612495748, endTime:1612550188, sourceType:'video/mp4' }, { id: 'c_G15', phone: '13222222225', nickname: 'UUUU', roomId: '2482', mediaUrl:'https://vjs.zencdn.net/v/oceans.mp4', startTime:1612495748, endTime:1612550188, sourceType:'video/mp4' }, { id: 'c_G16', phone: '13222222226', nickname: 'OOOO', roomId: '2482', mediaUrl:'https://vjs.zencdn.net/v/oceans.mp4', startTime:1612495748, endTime:1612550188, sourceType:'video/mp4' }, ], msg: '' } // 毫秒转化时分秒 const formatDuring = (mss) => { // var days = parseInt(mss / (1000 * 60 * 60 * 24)); let hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); if (hours < 10) { hours = `0${hours}`; } let minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60)); if (minutes < 10) { minutes = `0${minutes}`; } let seconds = parseInt((mss % (1000 * 60)) / 1000); if (seconds < 10) { seconds = `0${seconds}`; } return `${hours}:${minutes}:${seconds}`; }; const App = props => { // console.log({props}) const [currentVideoInfo, setCurrentVideoInfo] = useState({}); const [currentMasteroInfo, setCurrentMasterInfo] = useState({}); // const [ mediaUrl, setMediaUrl ] = useState([]); // 视频的url const [timeValue, setTimeValue] = useState(0); // 视频播放时间 const [isPlay, setIsPlay] = useState(false); // 是否播放 const [videoList, setVideoList] = useState([]); const [copyVideoList, setCopyVideoList] = useState([]); const [videoStartTime, setVideoStartTime] = useState(0); // 最长的视频开始时间戳 // const [meetingInfo, setMeetingInfo] = useState(meetinginfo); const [maxTime, setMaxTime] = useState(0); let { current } = useRef({ timer: '' }); const childMethodRef = useRef(); // const handleMeetingRoom = async () => { handleMeeting(meetingInfo) handleObtainTime() } // 获取视频长度 const handleObtainTime = async () => { const list = meetingInfo; // console.log({list}) // setAllVideoList(list) const start = Math.min.apply(Math, list.map(item => { return item.startTime })) const end = Math.max.apply(Math, list.map(item => { return item.endTime })) const time = end - start setVideoStartTime(start) setMaxTime(time) // console.log({start, end, time}) } const handleMeeting = async info => { const userList = info // console.log('userList[0]', userList[0]) // if (userList[0].mediaUrl) { // 筛选出候选人 const candidateInfo = userList.filter(i => i.id.indexOf('c_') > -1) // console.log({candidateInfo}) setCurrentVideoInfo({ ...candidateInfo[0] }) setVideoList([...candidateInfo]) // 候选人列表 setCopyVideoList(JSON.parse(JSON.stringify(candidateInfo))) // } // handleObtainTime(userList) } // 候选人切换变化 const handleChangeCandidateVideo = (type) => { if (videoList.length === 1) { message.info('只有一个候选人哦~') return } let index = 0 for (let i in copyVideoList) { if (copyVideoList[i].nickname === currentVideoInfo.nickname) { index = Number(i) } } // console.log(index, copyVideoList[index + 1], videoList) if (type === 'right') { if (index === (videoList.length - 1)) { childMethodRef.current.hanldeChangeListVideo(copyVideoList[0], videoList, 0, '1'); } else { childMethodRef.current.hanldeChangeListVideo(copyVideoList[index + 1], videoList, index + 1, '1'); // setCurrentVideoInfo(videoList[index + 1]) } } else { if (index === (0)) { childMethodRef.current.hanldeChangeListVideo(copyVideoList[videoList.length - 1], videoList, videoList.length - 1, '1'); // setCurrentVideoInfo(videoList[videoList.length - 1]) } else { childMethodRef.current.hanldeChangeListVideo(copyVideoList[index - 1], videoList, index - 1, '1'); // setCurrentVideoInfo(videoList[Number(index) - 1]) } } } useEffect(() => { handleMeetingRoom() }, []) // console.log('currentVideoInfo', currentVideoInfo) return ( <div className='analyze-container'> <div className='analyze-content'> <div className='playback-content'> <VideoLeft ref={childMethodRef} videoList={videoList} handleChangeCandidateVideo={handleChangeCandidateVideo} currentVideoInfo={currentVideoInfo} currentMasteroInfo={currentMasteroInfo} setCurrentVideoInfo={setCurrentVideoInfo} setCurrentMasterInfo={setCurrentMasterInfo} handleChangeMasterVideo={handleChangeMasterVideo} formatDuring={formatDuring} timeValue={timeValue} setTimeValue={setTimeValue} current={current} setIsPlay={setIsPlay} isPlay={isPlay} maxTime={maxTime} /> </div> </div> </div> ) } export default App;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。