弹框内容根据数组加载多视频流(http-flv)直播,动态生成dom并具有断线重连功能,关闭弹窗销毁全部流文件以及断线重连,即使释放内存,以防冗余逻辑导致内存溢出
安装:
npm install --save flv.js
引入(main.js);
import flvjs from 'flv.js';
Vue.prototype.$flvjs = flvjs;
Html:
<template>
<div style="width: 100%;height:100%;position: relative;">
<!--触发dom-->
<img @click="openLive()" src="../../assets/images/live.png" alt="" style="width: 60px;position: absolute;top: 18px;cursor:pointer">
<!--vue抽屉-->
<el-drawer
title="直播列表"
:visible.sync="drawer"
@close="drawClosed"
size="60%"
>
<div class="videoList">
<div v-for="(n,index) in getAllAcraftData" style="width:calc(50% - 20px);float:left;height: 200px;margin: 5px;margin-bottom: 50px;">
<p style="width: 100%;height: 30px;line-height: 30px;background: #000;color: #fff;text-indent: 15px;"> {{n.aircraft?n.aircraft.name :'空名称'}}</p>
<video
:id="'refVideoJsItem'+ index"
:ref="'refVideoJsItem'+ index"
class="video-js vjs-default-skin vjs-big-play-centered"
controls
muted
style="width:100%;height: 100%;"
preload="auto">
</video>
</div>
</div>
</el-drawer>
</div>
</template>
Css:
.videoList{
padding:0 20px;
height: 76vh;
overflow-y: scroll;
}
Data:
data() {
return {
drawer: false,
requireFlv:[],
getAllAcraftData:[],
timerCount:null,
player:null,
_player :[],
}
}
Method:
Created(){
this.getData();
},
methods: {
// 请求页面数据 这里根据自己项目情况写
getData(){
this.$api.getData().then( res =>{
this.getAllAcraftData = res.data || [];
// 事件循环
if(this.timerCount ){
clearTimeout(this.timerCount );
}
this.timerCount = setTimeout(this.getData,3000)
})
},
// flv 直播方法调用
openLive(){
const _this = this;
_this.drawer = true;
_this._player = [];
async function videoHLSURL() {
// 暂停重新赋值
_this.getAllAcraftData.forEach((data,index) =>{
const dom = 'refVideoJsItem' + index;
if (_this.$flvjs.isSupported()) {
var videoElement = document.getElementById(dom);
var pl = '';
f();
function f() {
pl = creatFlv(videoElement,data.liveUrl);
if (data.liveUrl !== "" && data.liveUrl !== null) {
pl.attachMediaElement(videoElement);
pl.load();
pl.play();
}
pl.on( _this.$flvjs.Events.ERROR, (errType, errDetail) => {
console.log("重新连接中...");
//视频出错后销毁重新创建
if (pl) {
// 销毁
if(_this.requireFlv[index]) {
clearTimeout(_this.requireFlv[index])
}
// 重建
_this.requireFlv[index] = setTimeout(()=>{
_this.destoryVideo(pl)
f();
},3000 );
}
});
}
_this._player.push(pl)
// 初始化flv
function creatFlv(videoElement,url) {
return _this.$flvjs.createPlayer({
type: "flv",
isLive: true,
fluid: true,
stashInitialSize: 128,// 减少首桢显示等待时长
url: url
},{
enableWorker: false, //不启用分离线程
enableStashBuffer: false, //关闭IO隐藏缓冲区
reuseRedirectedURL: true, //重用301/302重定向url,用于随后的请求,如查找、重新连接等。
autoCleanupSourceBuffer: true //自动清除缓存
});
}
}
})
};
setTimeout(
videoHLSURL
,300);
},
// 视频源定向销毁
destoryVideo(pl) {
pl.pause();
pl.unload();
pl.detachMediaElement();
pl.destroy();
pl = null;
},
// 视频源全局销毁
destoryVideoAll(){
if (this._player) {
this._player.forEach((data,i) =>{
this.destoryVideo(this._player[i])
})
}
},
// 断线重连销毁-关闭弹窗调用
drawClosed(){
this.clearFlv();
},
//断线重连销毁方法
clearFlv(){
if(this.requireFlv.length > 0 ) {
this.requireFlv.forEach( (data,index)=>{
if(this.requireFlv[index]) {
clearTimeout(this.requireFlv[index])
}
})
this.requireFlv = []
}
},
beforeDestroy(){
if(this.timerCount) {
clearTimeout(this.timerCount); //关闭
}
if (this._player) {
this.destoryVideoAll()
}
// 销毁
this.clearFlv();
},
}