由于最近接了个项目里面需要观看视屏记录学分等功能,就想着用video.js来进行观看视屏,但是网上查询用到的都是原生的,这边来增加一个通过react hooks进行观看视屏的配置 ,并展示如何定时器更新并记录观看视屏的进度,并且阻止拖动进度条快进功能⬇️
禁止拖动的关键代码
判断当前看视屏的最大事件 接口获取,如果没有最大进度就为0,每次拖动获取当前时间,如果大于最大2,就表示快进了,回到当前的最大事件,如果不大于,并且当前时间大于最大时间,则把当前最大的时间设置为现在观看的时间
let maxTime = dataDetail?.view_duration || 0;
// 监听播放进度事件
player.on('timeupdate', function () {
let currentTime = this.currentTime();
let duration = this.duration();
if (currentTime - maxTime > 2) {
this.currentTime(maxTime);
} else {
if (currentTime > maxTime) {
maxTime = this.currentTime();
}
}
//lastProcess为传给后端的进度字段
//lastProgress = currentTime / duration;
});
5秒实时更新的关键代码
videojs中自带ready函数,触发定时器接口更行,挂载intervalHandle是为了在离开页面时取消更新,不然会一直更新下去
let intervalHandle = useRef();
const player = videojs(
videoRef.current,
optiones,
function onPlayerReady() {
intervalHandle.current = setInterval(() => {
upDateProgress(lastProgress, maxTime);
}, 5000);
}
useEffect(() => {
return () => {
clearInterval(intervalHandle.current);
};
}, []);
切换视屏观看倍速配置
因为我用的是video.js 8.0 所以有两种办法
1、最简单的 在options中增加 playbackRates: [0.5, 1, 1.5, 2], 属性,注意!老版本只需要增加以上属性,但是8.0还需要在下一层的controlBar中增加{name:'playbackRateMenuButton',}
let optiones = {
playbackRates: [0.5, 1, 1.5, 2],
controlBar: {
children: [
{
name:'playbackRateMenuButton',
},
],
},
};
2、第二种是因为一开始我没有用{name:'playbackRateMenuButton'},导致我以为属性不可用了,所以先手写了一套,也是可以使用的
说一下第二种切换倍速的我的思想与代码,在渲染videojs播放器时,插入原生代码并且附带videojs的css,这样可以避免复杂的修改样式,然后再进行onchange事件触发videojs自带的playbackRate属性来进行修改视屏的倍速,但是由于原生代码中的onchange事件不能直接找到react中写的函数,所以我们需要通过监听切换倍速的点击事件来触发我们的函数,这边我们是给select加了个myselect的id,并且addTool要在onPlayerReady函数中触发
const rateChange=(params) =>{
console.log(params,'params');
let myselect = document.getElementById('myselect')
var index = myselect.selectedIndex
var selectedValue =myselect.options[index].value
const player = videojs(videoId)
player.ready(function() {
var _this = this
//速率
setTimeout(function() {
_this.playbackRate(Number(selectedValue));
},20);
});
setVideoSpeed(Number(selectedValue))
console.log(myselect,index,selectedValue,Number(selectedValue),'index');
}
const addTool = () => {
let divSFYX2 = document.createElement('div');
divSFYX2.innerHTML = `<button class="vjs-control " id="danmu_send_opt"><select id='myselect' style="-webkit-appearance: none;background-color: transparent;border: none;border-radius: 0px" change="rateChange(this.options[this.options.selectedIndex].value)">\n' +
' <option value ="1">1.0X</option>\n' +
' <option value ="1.25">1.25X</option>\n' +
' <option value="1.5">1.5X</option>\n' +
' <option value="2.0">2.0X</option>\n' +
'</select></button>`;
//监听点击事件来出发切换倍速函数
divSFYX2.addEventListener('change', (e)=>rateChange(e));
if (!addTools) {
//在bar中插入创建的div
document.querySelector('.vjs-control-bar')?.appendChild(divSFYX2);
setAddTools(true)
} else {
console.log('已经添加了');
}
};
下面是完整代码 👇
import { useLocation } from 'react-router';
import videojs from 'video.js';
import 'video.js/dist/video-js.css';
const zh = require('video.js/dist/lang/zh-CN.json');
zh['Picture-in-Picture'] = '画中画';
videojs.addLanguage('zh-CN', zh);
let intervalHandle = useRef();
const videoRef = useRef();
//刚进入页面通过接口获取视屏的url
const [videoUrl, setVideoUrl] = useState('');
//获取看到的视屏的详情(包括进度)
const [dataDetail, setDataDetail] = useState({});
//state为其他页面穿参,优先级考前,看你当前需求 可以删除
const { state } = useLocation();
//useEffect中配置video.js
useEffect(() => {
let optiones = {
controls: true,
autoplay: false, //视频是否自动播放安卓12无效
preload: 'auto',
language: 'zh-CN',
contextmenu: false,
width: document.body.clientWidth,
playbackRates: [0.5, 1, 1.5, 2],
controlBar: {
// timeDivider: true,//是否显示时间控制条,默认为true
// remainingTimeDisplay: false,//是否显示剩余时间,默认为true
// fullscreenToggle: true // 全屏按钮
children: [
//自定义
{ name: 'playToggle' }, // 播放按钮
{
name: 'volumePanel', // 音量控制
inline: false, // 不使用水平方式
},
{ name: 'currentTimeDisplay' }, // 当前已播放时间
{ name: 'durationDisplay' }, // 总时间
{ name: 'progressControl' }, // 播放进度条
{
name: 'pictureInPictureToggle', //支持画中画
},
{
name:'playbackRateMenuButton',
},
{
name: 'FullscreenToggle', //支持全屏
},
],
},
};
if (videoUrl) {
//判断之前开到的最大时间
let maxTime = state?.watchProgress || dataDetail?.view_duration || 0;
const player = videojs(
videoRef.current,
optiones,
function onPlayerReady() {
this.src(videoUrl); //视频url
this.poster(''); //视频封面图
// this.landscapeFullscreen(); // github上说解决横屏播放 但是没起作用
let lastProgress;
//第二种增加倍速的方法
// addTool();
console.log(dataDetail?.view_duration, '123');
this.currentTime(maxTime);
// 监听播放进度事件
player.on('timeupdate', function () {
let currentTime = this.currentTime();
let duration = this.duration();
if (currentTime - maxTime > 2) {
this.currentTime(maxTime);
} else {
if (currentTime > maxTime) {
maxTime = this.currentTime();
}
}
lastProgress = currentTime / duration;
});
//每五秒触发一次更新接口更新看到的视屏进度
intervalHandle.current = setInterval(() => {
upDateProgress(lastProgress, maxTime);
}, 5000);
},
);
return () => {
//销毁控制视频高度
if (player) {
player.dispose();
}
};
}
}, [videoUrl]);
//离开页面取消更新
useEffect(() => {
return () => {
clearInterval(intervalHandle.current);
};
}, []);
//挂载并且播放视屏
<div style={{ width: '100%', height: '100%' }} data-vjs-player>
<video
ref={videoRef}
id="videoId"
className="video-js"
playsInline={true}
></video>
</div>
如果要在进度条展示当前观看时间,需要在css中进行处理
:global{
.video-js{
width: 100%;
height: 100%;
}
.video-js .vjs-duration, .vjs-no-flex .vjs-duration {
display: inline-block;
}
.video-js .vjs-current-time, .vjs-no-flex .vjs-current-time {
display: inline-block;
}
.ant-tabs-nav::before{
border-bottom: 0px !important;
}
}