videojs依赖安装
npm install video.js --save
import "video.js/dist/video-js.css";
import video_zhCN from "video.js/dist/lang/zh-CN.json";
import videoJS from "video.js";
videoJS.addLanguage("zh-CN", video_zhCN); //设置播放器的语言
videojs初始化
1、html结构
2、通过js的方式进行初始化
/**
* 播放器初始化
*/
initVideoJS(videoId = "videoJS_1") {
let vm = this;
try {
let video = document.getElementById(videoId);
let options = {
controls: true, //是否显示播放器控件
autoplay: true, //是否自动播放
width: 864, //视频的宽度
height: 486,//视频的高度
aspectRatio: "16:9", //视频的宽高比
poster: this.currentVideo.bigthumbnailURL, //视频的封面
controlBar: { //底部的控制栏组件
currentTimeDisplay: true, //当前播放事件
timeDivider: true, //当前播放时间与总时间的斜杆分隔符
durationDisplay: true, //是否显示总时间
remainingTimeDisplay: false, //是否显示剩下的时间,该选项与是否显示总时间二选一
volumePanel: { //音量组件
inline: true //可以调整方向为纵向或者横向
},
children: [ //children数组这是controlbar的子元素顺序
{
name: "playToggle"
},
{
name: "volumePanel"
},
{
name: "currentTimeDisplay"
},
{
name: "progressControl"
},
{
name: "durationDisplay"
},
{
name: "playbackRateMenuButton",
playbackRates: [0.5, 1, 1.5, 2]
},
{
name: "FullscreenToggle"
}
]
},
sources: [ // 设置视频的播放源
{
src: this.qualityArray[0].url,
type: `video/mp4`, //注意有些类型不兼容如:video/mov
poster: this.currentVideo.bigthumbnailURL //视频封面
}
]
};
this.vPlayer = videoJS(video, options, function() {
this.on("error", () => {
//视频错误监听事件
});
this.on("loadstart", () => {
//视频开始加载数据监听事件
});
this.on("canplaythrough", () => {
//视频可以播放监听事件
});
this.on("playing", () => {
// 视频正在播放监听事件
});
this.on("stalled", () => {
console.log("网络异常");
});
this.on("waiting", () => {
//视频正在加载事件
});
});
/***
* 添加视频清晰度
****/
const controlBar = this.vPlayer.getChild("ControlBar") || null;
const qualityButton = new QualityMenuButton(this.vPlayer, {
qualitys: vm.qualitys, //传入视频的画质信息
defaultQuality: vm.qualitys[0] //传入视频的默认画质
});
if (controlBar) {
controlBar.addChild(
qualityButton,
{},
controlBar.children().length - 2
);
}
} catch (err) {
console.log(`initVideoJs Player error => ${err}`);
}
},
切换视频
1、在原来的video元素基础上进行切换
该方式使用以创建好的video标签,只是简单的改变video的src。注意,此时的自定义组件(如清晰度)并没有更新,里面的数据还是上一个视频的信息,需要手动更新,可以手动移除后再添加。
/**
* video.js切换视频
*/
switchVideo(url, seekTime = 0, qualityNname) {
let vm = this;
// 注意这里的id为页面渲染出来的video标签的id,可在控制台审查元素进行查看
let $video = document.getElementById(
`videoJS_${this.videoIndex}_html5_api`
);
//设置视频封面
this.vPlayer.posterImage.setSrc(
this.currentVideo.bigthumbnailURL || this.currentVideo.thumbnailURL
);
// 设置视频的src
$video.setAttribute("src", url);
this.vPlayer.load();
this.vPlayer.play();
},
2、创建新的video元素切换视频
该方式首先会调用dispose方法销毁已经创建的video标签,并移除所有的组件和监听事件,然后需要自己创建video并设置其id(注意该id不能与之前销毁的id相同,我也不知道为啥~ :) )和class以及src,然后将创建的video添加到文档中,如上html的结构,将作为id= vWrap的子元素添加到文档中。
createdVideoPlayer() {
let vm = this;
if (this.vPlayer) {
this.vPlayer.dispose();
}
this.videoIndex++; //每次创建的video中id不能和之前销毁的一样
let videowrap = document.getElementById("vWrap");
let videoTag =
document.getElementsByTagName("video")[0] ||
document.createElement("video");
videoTag.id = `videoJS_${this.videoIndex}`;
videoTag.autoplay = true;
videoTag.src = this.qualityArray[0].url;
videoTag.className += " video-js vjs-big-play-centered";
videowrap.appendChild(videoTag);
let options = {
controls: true,
autoplay: true,
width: 864,
height: 486,
aspectRatio: "16:9",
poster: this.currentVideo.bigthumbnailURL,
controlBar: {
currentTimeDisplay: true,
timeDivider: true,
durationDisplay: true,
remainingTimeDisplay: false,
volumePanel: {
inline: true
},
children: [
{
name: "playToggle"
},
{
name: "volumePanel"
},
{
name: "currentTimeDisplay"
},
{
name: "progressControl"
},
{
name: "durationDisplay"
},
{
name: "playbackRateMenuButton",
playbackRates: [0.5, 1, 1.5, 2]
},
{
name: "QualitySelectorBar"
},
{
name: "FullscreenToggle"
}
]
},
sources: [
{
src: this.qualityArray[0].url,
type: `video/mp4`,
poster: this.currentVideo.bigthumbnailURL
}
]
};
this.vPlayer = videoJS(
document.getElementById(`videoJS_${this.videoIndex}`),
options,
function() {
this.on("error", () => {
console.log("视频播放失败");
});
this.on("loadstart", () => {
});
this.on("playing", () => {
});
this.on("stalled", () => {
console.log("网络异常");
});
this.on("loadstart", () => {
});
this.on("waiting", () => {
});
this.on("playing", () => {
});
}
);
}
videojs自定义组件
1、视频清晰度切换组件(仿照官方的倍速切换组件实现)
清晰度菜单
// QualityMenuItem.js
import videoJS from "video.js";
import TipPanel from "./TipPanel";
class QualityMenuItem extends videoJS.getComponent("MenuItem") {
constructor(player, options) {
const label = options.quality.name;
const defaultLabel = options.defalutQuality.name;
options.multiSelectable = false;
options.label = label;
options.selected = label === defaultLabel;
// options.selectable = true; //使得菜单可以选中,主要是显示选中时的状态,由于选中后在选其他导致点击过的都显示选中状态(options.multiSelectable = false 不生效?),因此,我在项目中不开启~
super(player, options);
this.label = label;
this.defaultLabel = defaultLabel;
this.defalutQuality = options.defalutQuality;
this.qualityUrl = options.quality.url || "";
this.videoJSId = this.options_.videoJSId;
this.tipBar = new TipPanel();
this.on("loadedmetadata", this.updateLabel);
}
handleClick() {
super.handleClick();
this.changeVideoQuality();
}
changeVideoQuality() {
let vm = this;
// 这里应该是更新显示的清晰度标签,但是没用~ :(
// super.options_.label = this.options_.label;
// 选中该清晰度
// this.showLabel = this.options_.label;
// 更新显示的清晰度
if (document.querySelector(".vjs-quality-value").innerHTML === this.label) {
return; //点击当前清晰度则不执行
}
// 点击后不知道怎么更新显示的清晰度标签,因此我直接更新dom (原谅我太菜了~)
document.querySelector(
".vjs-quality-value"
).innerHTML = this.options_.label;
this.selected(
this.label === document.querySelector(".vjs-quality-value").innerHTML
);
let player = this.player();
let seekTime = player.currentTime();
let $video = document.getElementById(`${this.videoJSId}_html5_api`);
player.addChild(this.tipBar);
this.tipBar.notice(`正在切换至 ${this.label} 画质`);
// 切换清晰度,隐藏视频封面
player.posterImage.setSrc("");
$video.setAttribute("src", this.qualityUrl);
player.load();
player.currentTime(seekTime);
player.on("loadedmetadata", function() {
player.play();
player.currentTime(seekTime);
vm.tipBar.notice(`已经切换至 ${vm.label} 画质`);
vm.tipBar.hideNotice(); //默认2s移除提示信息
});
}
updateLabel() {
// this.selected(this.label === this.defaultLabel);
}
}
QualityMenuItem.prototype.contentElType = "button";
export default QualityMenuItem;
总结
一开始在项目中使用dplayer做为视频的播放库,但是由于在孤儿浏览器上出现兼容问题 ,因此不得不放弃转为videojs,一路走来,踩了不少抗,主要是视频切换和自定义组件在切换视频时出的问题(样式的修改可以通过css覆盖生成的样式),这篇文章谨献给自己在这里所掉的头~