🍉 xgplayer 官网:https://v3.h5player.bytedance.com/
🏠 github:https://github.com/bytedance/xgplayer/
需求
😉😉
做一个长这样的,播放ws视频,视频统一封面图,点击播放、全屏,点击查看更多查看所有视频
使用到的依赖
"xgplayer": "^2.32.2",
"xgplayer-flv": "^2.5.3",
"xgplayer-flv.js": "^2.3.0"
依赖的使用
RtspPlayer.vue
// 视频组件 RtspPlayer.vue
<template>
<div
class="videoContent"
:id="elId"
></div>
</template>
<script>
import FlvJsPlayer from 'xgplayer-flv.js';
import { v4 } from 'uuid'; // 用来生成 id ,避免 key 重复
export default {
name: 'CusPlayer',
components: {},
data() {
return {
player: null, // player 对象
elId: '', // id
currentIndex: null, // 当前被点击的视频 index
};
},
props: {
clickPlay: {
type: Boolean,
default: false,
}, // 父组件传来的,表示该视频的 播放按钮 被点击
isFull: {
type: Boolean,
default: false,
}, // 父组件传来的,表示该视频的 全屏按钮 被点击
index: {
type: Number,
}, // 父组件传来的,表示被点击视频的 index
},
created() {
this.elId = v4(); // 避免 key 重复
},
methods: {
createPlayer(url, coverPage) {
if (!url) {
return;
}
let self = this;
this.player = new FlvJsPlayer({
id: this.elId,
url: url,
autoplayMuted: false, // 静音播放
poster: coverPage, // 封面图
videoInit: true, // 没有封面图时,用第一帧
fitVideoSize: 'auto',
fluid: true,
autoplay: false, // 自动播放
isLive: true,
screenShot: false,
controls: false, // 控制条
whitelist: [''],
ignores: ['time'],
customConfig: {
isClickPlayBack: false,
},
flvOptionalConfig: {
enableWorker: true,
enableStashBuffer: false, //关闭缓存
stashInitialSize: 2048, //缓存大小2m
lazyLoad: false,
lazyLoadMaxDuration: 40 * 60,
autoCleanupSourceBuffer: true,
autoCleanupMaxBackwardDuration: 35 * 60,
autoCleanupMinBackwardDuration: 30 * 60,
},
});
this.player.on('play', function () {
// 为了解决 bug1
// 打开弹窗时,如果没点击的情况下,每一个视频都暂停
if (self.currentIndex === null) {
self.player.pause();
}
});
this.player.on('error', e => {
console.log(e, 'eeeeeeeeeeee');
});
document.addEventListener('contextmenu', function (e) {
e.preventDefault();
});
this.player.on('requestFullscreen', () => {});
this.player.on('exitFullscreen', () => {
// 让父组件把 isFull[index] 设置为 false,全屏按钮才能多次点击
this.$emit('nowIsfullScreen', this.currentIndex);
});
},
closePlayer() {
if (this.player) {
this.player.destroy();
this.player = null;
}
},
},
beforeDestroy() {
this.player.destroy();
},
watch: {
index(newVal) {
this.currentIndex = newVal;
},
clickPlay(newVal) {
if (newVal) {
// DOMException: The play() request was interrupted by a call to pause().
// 在弹窗中,如果点击第一页的视频,但该视频播放不了,再点击第二页的视频,不 catch 会报错
let playPromise = this.player.play();
if (playPromise) {
playPromise
.then(() => {
// 播放成功
// 因为项目中很多视频都播放不了,父组件别把播放按钮消失
this.$emit('videoSuccess', this.currentIndex);
})
.catch(() => {});
}
}
},
isFull(newVal) {
if (newVal) {
// 不写 this.player.root 全屏不好使
this.player.getFullscreen(this.player.root);
}
},
},
};
</script>
RealMonitor.vue
<div class="card">
<div class="item-video">
<div class="video">
<CusPlayer
:ref='`videoRef${index}`'
:clickPlay="clickPlay[index]"
:isFull="isFull[index]"
:index="currentIndex"
@nowIsfullScreen="nowIsfullScreen"
@videoSuccess="videoSuccess"
></CusPlayer>
</div>
<div class="pause">
<img
v-if="!isSuccess[index]"
src="@/assets/monitoPause.png"
@click="pauseHandle(index)"
>
</div>
<div class="mask">
<img
class="mask-img"
src="@/assets/monitoMask.png"
>
<div class="full">
<img
class="full-img"
src="@/assets/monitoFull.png"
@click="fullScreenHandle(index)"
>
</div>
</div>
</div>
</div>
data() {
return {
clickPlay: [], // 用来记录 video 被点击播放按钮
isFull: [], // 用来记录 video 被点击全屏按钮
isSuccess: [], // 用来记录 video 播放成功
currentIndex: null,
videoList: [{ name: '' }, { name: '' }, { name: '' }, { name: '' }],
};
},
// 向接口请求数据
async getrequests() {
try {
this.clickPlay = [];
this.isFull= [];
this.isSuccess= [];
const res = await getMonitor();
if (res.data.code === 200) {
const dataList = res.data.data;
dataList.slice(0, 4).forEach((item, index) => {
this.clickPlay.push(false);
this.isFull.push(false);
this.isSuccess.push(false);
// 调用 createVideo 方法,生成video
this.createVideo(index, item.playerUrl, item.cover);
this.videoList[index] = this.videoList[index] || {};
this.videoList[index].name = item.remark;
});
} else {
console.log('请求失败');
}
} catch (error) {
console.log(error, '请求失败');
}
},
// 创建video
createVideo(index, url) {
this.$nextTick(() => {
// 调用组件方法
this.$refs[`videoRef${index}`][0].createPlayer(url, cover);
});
},
// 监听 “播放” 按钮
pauseHandle(index) {
this.currentIndex = index;
Vue.set(this.clickPlay, index, true);
},
// 监听 “全屏” 按钮
fullScreenHandle(index) {
this.currentIndex = index;
Vue.set(this.isFull, index, true);
},
// 监听 退出全屏
nowIsfullScreen(index) {
Vue.set(this.isFull, index, false);
},
// 视频播放成功
videoSuccess(index) {
Vue.set(this.isSuccess, index, true);
},
⭐️ 弹窗中同理,没有什么特殊的
Bug
弹窗中视频自动播放
👾👾
在主页面(父组件)上的视频,不会自动播放
在弹窗中的视频,设置了 autoplay = false ,也会自动播放
在视频组件中监听 play 事件
如果视频播放了,且没有点击过任何视频,即 currentIndex = null
就将该视频暂停
DOMException: The play() request was interrupted by a call to pause().
👾👾
在弹窗中,如果点击第一页的视频,如果该视频播放不了
再点击第二页的视频,会报错
play() 的返回值是 promise 对象,catch 一下
鼠标右键失效
👾👾
将接口请求 try catch 一下