vue前端对接监控视频 FLV格式
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
接触智慧园区,智慧工地,水泵站等项目之后,发现都有实时监控的对接,并且是可以多屏进行,就研究了相关的技术栈,找到了这个强大的播放器对前端还是很友好的,话不多说上干货!!!
提示:代码片段里有博主对的接口,读代码的时候注意
1. 使用npm 、cnpm、yarn 下载如下插件
2. npm install xgplayer
3. npm install xgplayer-flv
4. npm install xgplayer-flv.js
代码如下(示例):
import Player from "xgplayer"; // 这是他的一个方法
import FlvPlayer from "xgplayer-flv"; // 这个是搭配上面哪个使用的
import 'xgplayer/dist/index.min.css' // 这个是播放器的样式 ,可以在当前页面使用,也可以放全局
let a = new Player({
id: this.playList[0].id,// 对应
isLive: true, // 是否是直播,
plugins: [FlvPlayer], // 视频播放的方式
url: '你的视屏地址', // 地址
autoplay: true, //
lang: "zh-cn", // 是否自动播放,
autoplayMuted: true,//是否自动静音自动播放
screenShot: true, //是否使用截图插件
rotate:false,//是否使用旋转插件
download:false,//是否使下载按钮
pip:false,//是否使用画中画插件
mini:false,//是否启用mini小窗插件
playbackRate:[0.5, 0.75, 1, 1.5, 2],//倍速插件显示列表
});
提示 :这里用到了Element-ui的tree组件,还有博主自己写一些样式就直接拿过来的 取自己用的即可
代码如下(示例):
<template>
<div class="list">
<div class="lsieqqwe">
<div class="boseList bgImg">
<span
@click="getall"
style="color: #fff; margin-left: 12px; font-size: 16px"
>设备分组span
>
div>
<div style="padding: 5px">
<el-input
v-model="deptName"
placeholder="请输入部门名称"
clearable
size="small"
prefix-icon="el-icon-search"
style="margin-bottom: 5px"
/>
div>
<div class="treeDataLsit">
<el-tree
class="filter-tree"
:data="treeData"
ref="tree"
:props="defaultProps"
node-key="id"
default-expand-all
:expand-on-click-node="false"
highlight-current
@node-click="handleNodeClick"
:filter-node-method="filterNode"
>
<span slot-scope="{ node, data }" class="customize-tree-p">
<div class="haha" v-if="node.level == 3">
<img
:src="
data.isOnline == 1
? '/img/isOnlinetrue.png'
: '/img/isOnlinefalse.png'
"
alt=""
/>
<span>{{ data.channelName }} span>
div>
<span v-else>{{ data.channelName }} span>
span>
el-tree>
div>
<div
style="
width: 100%;
height: 42%;
display: flex;
flex-direction: column;
position: relative;
"
>
<div
class="control toplst"
v-if="zheDielist"
@click="zheDielist = false"
>
<div>div>
<div>云台控制div>
<div><img src="@/assets/carmear/xiala.png" alt="" />div>
div>
<div v-if="zheDielist" style="height: 90%; flex: 1; margin-top: 65px">
<div class="control_list">
<img
@mousedown="cameraBtn(1)"
@mouseup="mouseup(1)"
class="ShArrows"
src="@/assets/jianTou/shang.png"
alt=""
/>
<img
@mousedown="cameraBtn(2)"
@mouseup="mouseup(2)"
class="XArrows"
src="@/assets/jianTou/xia.png"
alt=""
/>
<img
@mousedown="cameraBtn(3)"
@mouseup="mouseup(3)"
class="ZArrows"
src="@/assets/jianTou/zuo.png"
alt=""
/>
<img
@mousedown="cameraBtn(4)"
@mouseup="mouseup(4)"
class="YArrows"
src="@/assets/jianTou/you.png"
alt=""
/>
<img
@mousedown="cameraBtn(7)"
@mouseup="mouseup(7)"
class="YSArrows"
src="@/assets/jianTou/Yshang.png"
alt=""
/>
<img
@mousedown="cameraBtn(8)"
@mouseup="mouseup(8)"
class="YXArrows"
src="@/assets/jianTou/Yxia.png"
alt=""
/>
<img
@mousedown="cameraBtn(6)"
@mouseup="mouseup(6)"
class="ZXArrows"
src="@/assets/jianTou/Zxia.png"
alt=""
/>
<img
@mousedown="cameraBtn(5)"
@mouseup="mouseup(5)"
class="ZSArrows"
src="@/assets/jianTou/Zshang.png"
alt=""
/>
div>
<div class="footerLsitStyle_why">
<div
style="padding: 5px"
@mousedown="BigCamera(1)"
@mouseup="BigCameraMouseup(1)"
>
<img src="@/assets/jianTou/magnify.png" alt="" />
div>
<div
style="padding: 5px; border-left: 2px solid #1f4075"
@mousedown="BigCamera(2)"
@mouseup="BigCameraMouseup(2)"
>
<img src="@/assets/jianTou/reduce.png" alt="" />
div>
div>
div>
<div class="control footer" v-else @click="zheDielist = true">
<div>div>
<div>云台控制div>
<div><img src="@/assets/carmear/xiala.png" alt="" />div>
div>
div>
div>
<div style="width: 100%; padding: 10px">
<div class="carStyle">
<div class="shexinag">
<div style="margin-left: 40px; display: flex">
<div
style="padding: 6px; font-size: 17px"
:class="1 == 1 ? 'tableLIstStyle ' : 'table_hui'"
>
实时监控
div>
<div
style="padding: 5px; font-size: 17px"
:class="1 == 2 ? 'tableLIstStyle' : 'table_hui'"
>
录像回放
div>
div>
div>
div>
<ul :class="1 != 1 ? 'FenPingCenter_box' : 'FenPingCenter_list_box'">
<li
:class="
item == FenPingCenType ? 'FenPingCenter_Ui' : 'FenPingCenter_li'
"
v-for="(item, index) in IconFontNumber"
:key="item"
:style="{ width: 100 / IconFontTypenumber + '%' }"
>
<div class="FenPingLise" v-if="item == mouType">
<button @click="playerBtnItem(index)">关 闭button>
div>
<div
class="divVide"
:id="'FenPingCenter_li' + index"
@mouseenter="mouseenteBtn(item)"
@click="
FenPingCenClick({ type: item, Nme: 'FenPingCenter_li' + index })
"
>div>
li>
ul>
<div class="footer_box">
<div class="iconFlist_box">
<span style="color: #fff">分屏 : span>
<i
@mousedown="FenPing(item)"
v-for="item in IconFont"
:key="item.className"
:class="
item.number == IconFontNumber
? ` iconFlist ${item.className}`
: ` iconStyle ${item.className}`
"
>i>
div>
<div>
<ul class="operationUl">
<li
v-for="(item, index) in operationArray"
:key="index"
@click="FooterBtn(item)"
>
<div><img :src="item.image" alt="" />div>
<div>{{ item.name }}div>
li>
ul>
div>
div>
div>
div>
template>
data() {
return {
FenPingCenType: null, //
mouType: null,
destroyType: null,// 判断是否销毁
zheDielist: false, // 左侧云台控制显示
uuidv4: '',// uuid 视频放大时使用
treeData: [ // 左侧 tree 的数据
{
id: 1,
channelName: "全部",
children: [
],
},
],
// 图标
IconFontNumber: 1,
IconFontTypenumber: 1,
IconFont: [
{
className: 'iconfont icontiFenPingOne',
number: 1,
},
{
className: 'iconfont icontiFenPingSi',
number: 4,
},
{
className: 'iconfont icontiFenPingLiu',
number: 6,
},
],
operationArray: [ // 分屏数据
// {
// name: '抓拍',
// image: require('../../../assets/carmear/zhuapai.png')
// },
// {
// name: '放大',
// image: require('../../../assets/carmear/BigList.png')
// },
// {
// name: '录像',
// image: require('../../../assets/carmear/luxiang.png')
// },
// {
// name: '音频',
// image: require('../../../assets/carmear/yinpin.png')
// },
// {
// name: '对讲',
// image: require('../../../assets/carmear/duijiang.png')
// },
// {
// name: '全屏',
// image: require('../../../assets/carmear/qaunping.png')
// },
],
// tree 重置 数据的属性名
defaultProps: {
children: 'children',
label: 'channelName'
},
// 部门名称
deptName: undefined, // 用于筛选tree 数据
selectArry: '',
playList: [], // 所有视频的 实例
cameraName: null, // 判断是否选中视频
checkchannelId: null // 调取视频接口 接收 其他页面传过来的数据
};
},
// video 划入事件
mouseenteBtn(value) {
this.mouType = value;
console.log(11111)
},
// video 划入事件
mouseout() {
setTimeout(() => {
this.mouType = null
}, 1000)
},
提示:视频出来后 显示 全屏或者 抓拍的 按钮 这个块不需要 如果是就一个平并且需要写自己的全屏抓拍样式的话可以用道 这个播放器本身带这些功能 只是样式不好看
FooterBtn(FooterObj) {
console.log(FooterObj.name)
if (FooterObj.name == '全屏') {
//
this.playList[this.FenPingCenType - 1].ShiLi.getFullscreen()
} else if (FooterObj.name == '抓拍') {
let aasd = ""
// 这格式掉后端的接口
xxxx({ id: this.defaultPropsBtnBjc.deviceCode }).then(res => {
aasd = res.msg
window.open(aasd).download()
})
}
},
// 分屏按钮
FenPing(value) {
/*
1.当你点击下方的三个图标的时候,分别获取 4 ,3 ,1三个值
对应下面的三个判断
2. 将对应的盒子添加上是shili:'' ,id(对应的上每一个盒子),当前视频的状态
*/
this.IconFontNumber = value.number
console.log(value.number)
if (value.number == 4) {
this.IconFontTypenumber = 2
for (let index = 1; index < 4; index++) {
this.playList.push({ ShiLi: null, id: `${'FenPingCenter_li' + index}`, type: 0, flg: false })
}
} else {
this.IconFontTypenumber = 3
for (let index = 1; index < 6; index++) {
this.playList.push({ ShiLi: null, id: `${'FenPingCenter_li' + index}`, type: 0, flg: false })
}
}
if (value.number == 1) {
this.IconFontTypenumber = 1
this.playList = this.playList.splice(0, 1)
this.$forceUpdate()
}
},
playerBtnItem(index) {
console.log(index); // 这个index是下标
/**
1.实例销毁调用.ShiLi.destroy();这个方法
2.初始化当前的数据的状态
*/
this.mouType = null;
this.destroyType = true;
// // 视频的销毁
this.playList[index].ShiLi.destroy();
this.playList[index].ShiLi = null;
this.playList[index].flg = true;
this.playList[index].type = 0;
},
handleNodeClick(value) {
this.defaultPropsBtnBjc = value
console.log(value)
let a = []
/**
* 判断是否是tree的最里层的数据
*/
if (!value.children) {
this.playList.forEach(item => {
if (item.type == 1) {
a.push(item.type)
}
})
// 接口
xxxxx({ channelId: value.channelCode || this.checkchannelId }).then(res => {
let b = a.length
/**
* 判断是否是 选中 容器
* 如果选择容器
* 判断他是否为null 查找到他的下标
* 拿容器ID 生成 播放器实例
* 并且插入到 实例的数据组中
* 将播放状态 改为 1
* */
if (this.cameraName && !this.destroyType) {
let player = new Player({
id: this.cameraName,
isLive: true,
plugins: [FlvPlayer],
url: res.data.url,
autoplay: true,
lang: "zh-cn",
autoplayMuted: true,
"screenShot": true
});
this.playList[this.FenPingCenType - 1].ShiLi = player
this.playList[this.FenPingCenType - 1].type = 1
} else {
/**
* 判断是否是 是否是 销毁实例后
* 判断他是否为null 查找到他的下标
* 拿容器ID 生成 播放器实例
* 并且插入到 实例的数据组中
* 将播放状态 改为1
* */
if (this.destroyType) {
let iB = this.playList.findIndex(item => { return item.ShiLi == null })
console.log(iB, 'ppppppp', this.FenPingCenType)
if (this.FenPingCenType) {
this.playList[this.FenPingCenType - 1].ShiLi = new Player({
id: this.cameraName,
isLive: true,
plugins: [FlvPlayer],
url: res.data.url,
autoplay: true,
lang: "zh-cn",
autoplayMuted: true,
"screenShot": true
});
this.playList[this.FenPingCenType - 1].type = 1
this.destroyType = !this.playList.every(item => item.type == 1)
// this.classLList()
} else {
this.playList[iB].ShiLi = new Player({
id: this.playList[iB].id,
isLive: true,
plugins: [FlvPlayer],
url: res.data.url,
autoplay: true,
lang: "zh-cn",
autoplayMuted: true,
"screenShot": true
});
this.playList[iB].type = 1
this.destroyType = !this.playList.every(item => item.type == 1)
}
} else {
for (let i = 0; i < this.playList.length; i++) {
if (this.IconFontTypenumber == 1) {
this.playList.forEach(item => {
if (item.ShiLi != null) {
item.ShiLi.destroy();
item.ShiLi = null;
item.type = 0;
let a = new Player({
id: this.playList[0].id,
isLive: true,
plugins: [FlvPlayer],
url: res.data.url,
autoplay: true,
lang: "zh-cn",
autoplayMuted: true,
"screenShot": true,
});
item.ShiLi = a
}
return item
})
}
console.log(9999)
if (this.playList[i].ShiLi == null) {
this.playList[b].ShiLi = new Player({
id: this.playList[b].id,
isLive: true,
plugins: [FlvPlayer],
url: res.data.url,
autoplay: true,
lang: "zh-cn",
autoplayMuted: true,
"screenShot": true,
playsinline: true,
height: window.innerHeight,
width: window.innerWidth
});
this.playList[b].type = 1
break;
}
}
}
}
})
}
},
// 云台控制必须是球机-上下左右转动
cameraBtn(value) {},
// 停止事件xx`q
mouseup(value) {},
// 放大开始事件
BigCamera(value) {},
// 放大结束事件
BigCameraMouseup(value) {}
到此也就结束,使用代码片段的时候需要将图片替换一下不然会出现路径的问题