使用video.js重新封装视频播放器支持点播及直播
Posted 学而时习之.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用video.js重新封装视频播放器支持点播及直播相关的知识,希望对你有一定的参考价值。
一、安装指定版本是正常命令后加‘@版本号’
npm install videojs@7.15.4 --save
二,组件封装的代码
<template>
<div class="live-video-wrapt">
<div id="videoUpdate" class="video-show" v-show="!isError">
<video
id="videoTV"
class="video-js vjs-default-skin vjs-big-play-centered vjs-16-9"
preload="auto"
webkit-playsinline="true"
playsinline="true"
type="application/x-mpegURL"
allowsInlineMediaPlayback="YES"
webview.allowsInlineMediaPlayback="YES"
width="100%"
ref="videoRef"
x5-video-player-fullscreen="true"
:poster="posterSrc"
@timeupdate="onTimeupdate"
>
<source id="sourceBox" :src="videoSrc" ref="sourceTV" />
<p class="vjs-no-js">不支持播放</p>
</video>
</div>
<div v-show="isError" class="errorTip">
<p>视频出错了!</p>
<br />
<p> textError </p>
</div>
<!-- 底部操作栏 -->
<div v-show="!isError" class="tv-footer-btn">
<div class="tv-btn tv-left">
<!-- 播放和暂停 -->
<div class="iconfont" v-if="tvBtnShow.stop">
<div
class="btn-image"
@click="TVboting"
:style="
backgroundImage:
boting === true
? `url($require('./video-img/pause.png'))`
: `url($require('./video-img/pause-active.png'))`,
"
></div>
</div>
<!-- 播放下一个视频 -->
<div class="iconfont" v-if="tvBtnShow.next">
<div
class="btn-image"
:style="
backgroundImage:
nextBtn === true
? `url($require('./video-img/next.png'))`
: `url($require('./video-img/next-active.png'))`,
"
></div>
</div>
<!-- 直播刷新 -->
<div class="iconfont" v-if="tvBtnShow.update" @click="TVupdate">
<div class="btn-image update-btn"></div>
</div>
</div>
<!-- 视频进度条 -->
<div class="tv-btn tv-centre">
<el-slider
class="time-progress-bar"
v-if="tvBtnShow.bar"
v-dragvideo
v-model="timeVal"
:show-tooltip="false"
@change="onTimeChange"
style="width: 100%"
>
</el-slider>
</div>
<div class="tv-btn tv-right">
<!-- 音量 -->
<div class="iconfont icon-muted" v-if="tvBtnShow.music">
<div
class="btn-image"
@click="TVsound"
:style="
backgroundImage:
mutedIcon === true
? `url($require('./video-img/muted.png'))`
: `url($require('./video-img/muted-active.png'))`,
"
></div>
<div class="volume-state">
<div class="box">
<el-slider
class="progress-bar"
v-model="volumeVal"
vertical
:show-tooltip="false"
@input="onMutedInput"
height="5vw"
>
</el-slider>
</div>
</div>
</div>
<!-- 全屏 -->
<div class="iconfont" v-if="tvBtnShow.full">
<div
class="btn-image"
@click="TVFullScreen"
:style="
backgroundImage:
fullScreen === true
? `url($require('./video-img/full-screen-active.png'))`
: `url($require('./video-img/full-screen.png'))`,
"
></div>
</div>
</div>
</div>
</div>
</template>
<script>
/* eslint-disable */
import videojs from "video.js";
import video_zhCN from "video.js/dist/lang/zh-CN.json";
import video_en from "video.js/dist/lang/en.json";
import "video.js/dist/video-js.css";
import "videojs-contrib-hls";
export default
name: "videojs",
created()
// 直播类型
const type = this.videoSrc
.substring(this.videoSrc.lastIndexOf(".") + 1)
.split("?")[0];
const t = type.toLowerCase();
if (t === "m3u8")
this.tvBtnShow.update = true;
this.tvBtnShow.stop = false;
this.tvBtnShow.bar = false;
,
mounted()
const that = this;
console.log("视频地址", this.videoSrc);
//为避免在初始化video时播放源是空的,报播放源错误,需要先给source 的src赋值
let player = videojs("videoTV", that.playOptions, function ()
// player.controls(false);
// this.play();
setTimeout(() =>
//延时确保能监听到视频源错误
let mediaError = this.error();
if (mediaError != null && mediaError.code)
that.textError = mediaError.message;
console.log("播放失败", mediaError);
that.isError = true;
, 1000);
this.on("loadedmetadata", function ()
// console.log("loadedmetadata---视频源数据加载完成----");
);
this.on("loadeddata", function ()
// console.log("loadeddata---渲染播放画面----");
);
this.on("timeupdate", function (event)
// 监听视频播放进度,返回视频播放历史时间
that.$emit("historyTime", parseInt(this.currentTime()));
);
this.on("pause", function ()
that.boting = false;
);
this.on("play", function ()
that.boting = true;
);
this.on("fullscreenchange", function ()
that.fullScreen = this.isFullscreen_;
if (player.isFullscreen())
player.controls(true);
else
player.controls(false);
);
this.on("ended", function ()
that.boting = false;
console.log("ended---结束停止---");
that.isError = true;
);
);
videojs.addLanguage("zh-CN", video_zhCN);
videojs.addLanguage("en", video_en);
// player.on("click", function ()
// console.log("点击视频");
// ); //设置播放器宽度
,
beforeDestroy()
const videoDom = this.$refs.videoRef; //不能用document 获取节点
videojs(videoDom).dispose(); //销毁video实例,避免出现节点不存在 但是flash一直在执行,也避免重新进入页面video未重新声明
,
directives:
dragvideo:
bind(el, binding, vnode, oldVnode)
const els = el.querySelector(".el-slider__button-wrapper");
els.addEventListener("mousedown", (e) =>
const videoDom = videojs("videoTV");
videoDom.ready(function ()
let _this = this;
_this.pause();
);
els.addEventListener("mouseup", (e) =>
videoDom.ready(function ()
let _this = this;
_this.play();
);
);
);
,
,
,
props:
videoSrc:
type: String,
required: true,
,
posterSrc:
type: String,
required: false,
,
,
data()
return
timeVal: 0, // 视频进度条值
mutedIcon: false, // 是否静音
volumeVal: 100, // 音量进度条值
boting: false, //是否暂停
nextBtn: true, // 切换下一个
fullScreen: false, //是否全屏
tvBtnShow:
// 自定义操作按钮-Show
stop: true,
next: false,
update: false,
bar: true,
music: true,
full: true,
,
playOptions:
autoplay: false, //自动播放
loop: true, //循环播放
muted: false, //是否静音
bigPlayButton: true,
textTrackDisplay: true,
posterImage: true,
errorDisplay: false,
playbackRates: false,
// controls: true, //是否拥有控制条
// controlBar: false, //关闭默认控制条
controlBar:
// 设置控制条组件
/* 设置控制条里面组件的相关属性及显示与否
'currentTimeDisplay':true,
'timeDivider':true,
'durationDisplay':true,
'remainingTimeDisplay':false,
volumePanel:
inline: false,
*/
/* 使用children的形式可以控制每一个控件的位置,以及显示与否 */
children: [
name: "playToggle" , // 播放按钮
name: "liveDisplay" , //直播流时,显示LIVE
// name: "currentTimeDisplay" , // 当前已播放时间
// name: "progressControl" , // 播放进度条
// name: "durationDisplay" , // 总时间
//
// // 倍数播放
// name: "playbackRateMenuButton",
// playbackRates: [0.5, 1, 1.5, 2, 2.5],
// ,
//
// name: "volumePanel", // 音量控制
// inline: false, // 不使用水平方式
// ,
name: "FullscreenToggle" , // 全屏
],
,
,
textError: "",
isError: false,
;
,
methods:
TVboting()
//播放或暂停
let that = this;
const videoDom = videojs("videoTV");
videoDom.ready(function ()
let _this = this;
setTimeout(function ()
if (that.boting === true)
_this.pause();
that.boting = false;
else
_this.play();
that.boting = true;
, 20);
);
,
TVupdate()
// 直播刷新
this.$emit("TVupdate");
,
onTimeupdate(event)
// 调整声音进度条
this.timeVal = (event.target.currentTime / event.target.duration) * 100;
,
onTimeChange(e)
// 声音进度条值,发生改变
const totalTime = document.querySelector("#videoTV video").duration; // 视频总时长
document.querySelector("#videoTV video").currentTime =
(this.timeVal / 100) * totalTime;
console.log("实际", (this.timeVal / 100) * totalTime);
,
onMutedInput(e)
// 音量大小调整
document.querySelector("#videoTV video").volume = e / 100;
if (e !== 0)
this.mutedIcon = false;
else
this.mutedIcon = true;
,
TVsound()
// 是否静音
this.mutedIcon = !this.mutedIcon;
if (this.mutedIcon)
this.volumeVal = 0;
document.querySelector("#videoTV video").volume = 0;
else
this.volumeVal = 100;
document.querySelector("#videoTV video").volume = 0.1;
,
TVFullScreen()
// 全屏
let player = videojs("videoTV");
player.requestFullscreen();
player.isFullscreen(true);
,
TVsecond(time)
// 视频播放历史位置的时间
document.querySelector("#videoTV video").currentTime = time;
,
,
;
</script>
<style>
/* 全屏操作栏样式 */
.live-video-wrapt .video-show .video-js .vjs-control-bar .vjs-volume-panel
position: absolute;
right: 4em;
.live-video-wrapt
.video-show
.video-js
.vjs-control-bar
.vjs-fullscreen-control
position: absolute;
right: 0;
/* 时间进度条 */
.live-video-wrapt .tv-footer-btn .tv-centre .el-slider .el-slider__runway
background-color: rgba(0, 0, 0, 0.5);
margin: 0;
.live-video-wrapt
.tv-footer-btn
.tv-centre
.el-slider
.el-slider__runway
.el-slider__bar
background-color: white;
.live-video-wrapt
.tv-footer-btn
.tv-centre
.el-slider
.el-slider__runway
.el-slider__button-wrapper
.el-tooltip.el-slider__button
width: 0.5vw;
height: 0.5vw;
border: 2px solid white;
background-color: #de6f6f;
/* 声音进度条 */
.live-video-wrapt
.tv-footer-btn
.tv-btn
.iconfont
.volume-state
.box
.progress-bar
.el-slider__runway
background-color: black;
.live-video-wrapt
.tv-footer-btn
.tv-btn
.iconfont
.volume-state
.box
.progress-bar
.el-slider__runway
.el-slider__bar
background-color: white;
.live-video-wrapt
.tv-footer-btn
.tv-btn
.iconfont
.volume-state
.box
.progress-bar
.el-slider__runway
.el-slider__button-wrapper
.el-tooltip.el-slider__button
width: 0.5vw;
height: 0.5vw;
border: 2px solid white;
background-color: #de6f6f;
</style>
<style scoped>
.live-video-wrapt
width: 100%;
border-bottom: 1px solid #f0f0f0;
position: relative;
.video-show
width: 100%;
position: relative;
.video-show .video-js.vjs-playing .vjs-tech
pointer-events: auto;
.errorTip
font-size: 2rem;
width: 100%;
height: 100%;
min-height: 8vw;
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
/* 底部操作栏 */
.live-video-wrapt .tv-footer-btn
width: 100%;
box-sizing: border-box;
padding: 1vw;
display: flex;
justify-content: space-evenly;
position: absolute;
left: 0;
bottom: 10%;
.live-video-wrapt .tv-footer-btn .tv-btn
display: flex;
flex-wrap: wrap;
justify-content: space-around;
.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .btn-image
width: 3vw;
height: 3vw;
background: no-repeat scroll center;
background-size: 3vw 3vw;
display: flex;
justify-content: center;
align-items: center;
.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .update-btn
background-image: url(./video-img/update.png);
.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .update-btn:hover
background-image: url(./video-img/update-hover.png);
/* 音量进度条 */
.live-video-wrapt .tv-footer-btn .tv-btn .icon-muted
position: relative;
.live-video-wrapt .tv-footer-btn .tv-btn .icon-muted:hover .volume-state
display: block;
.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .volume-state
width: 3vw;
height: 7.25vw;
display: none;
position: absolute;
left: 0;
bottom: 3vw;
.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .volume-state .box
width: 3vw;
height: 7vw;
border-radius: 0.25vw;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
/* */
.live-video-wrapt .tv-footer-btn .tv-centre
width: 50%;
align-items: center;
.live-video-wrapt .tv-footer-btn .tv-left .iconfont
margin-right: 1vw;
.live-video-wrapt .tv-footer-btn .tv-right .iconfont
margin-left: 1vw;
</style>
直播
点播
文件夹结构
照片
以上是关于使用video.js重新封装视频播放器支持点播及直播的主要内容,如果未能解决你的问题,请参考以下文章