//海康监控视频非分屏需求,一个页面加载多个监控视频画面,
//调用后端接口实现动态多个监控画面显示并通过监听滚动事件监听来实现分页加载!;
//滚动事件: handleScroll
js文件位置
index.html 引入js文件
//根据自己路径引入哈
<script src="static/haiKangWeb3.0/jquery-1.7.1.min.js"></script>
<script type="text/javascript" id="videonode" src="static/haiKangWeb3.0/webVideoCtrl.js"></script>
新建子组件videoMonitorings.vue–(封装视频监控组件)
<template>
<div class="video">
<div :id="videoId" class="plugin"/>
</div>
</template>
<script>
import {WebVideo} from "../../../../public/static/haiKangWeb3.0/webVideo.js";
import {message} from "@/utils/message";
import {
reactive,
onMounted,
onBeforeUnmount,
onUnmounted,
toRefs,
ref,
watchEffect,
watch
} from "vue";
export default {
name: "index",
props: {
videoId: {
type: String
},
hkvInfo: {
type: Object || Array,
require: true
},
},
// emits:['changeFlag'],
setup(props, {emit}) {
const {dataList} = toRefs(props);
const hkvInfo = ref({});
const videoId = ref();
const channels = ref([])
const state = reactive({
webVideo: "",
web: {},
});
watch(props.hkvInfo, (newVal, oldvalue) => {
if (newVal) {
console.log('newVal', newVal)
hkvInfo.value = newVal
videoId.value = newVal.id;
let t = newVal.loadingTime || 1000
setTimeout(() => {
initS();
}, t)
} else {
initS();
}
}, {
deep: true,
immediate: true,
})
const initS = () => {
// 初始化
WebVideoCtrl.I_InitPlugin({
bWndFull: true, //是否支持单窗口双击全屏,默认支持 true:支持 false:不支持
iWndowType: 1,// 画面分割数 1 就是1*1 2就是2*2
cbSelWnd: function (xmlDoc) {
//此属性是窗口分割切换窗口时触发
// clickStartRealPlay();
// console.log("当前选择的窗口编号是1");
},
cbInitPluginComplete: function () {
WebVideoCtrl.I_InsertOBJECTPlugin(videoId.value).then(
() => {
// 检查插件是否最新
WebVideoCtrl.I_CheckPluginVersion().then((bFlag) => {
if (bFlag) {
let str = "检测到新的插件版本,双击开发包目录里的HCWebSDKPlugin.exe升级!"
message(str, {
type: "warning"
});
}
});
},
() => {
window.open('../../../../bin/VideoWebPlugin/HCWebSDKPlugin.exe');
let str1 = "插件初始化失败,请确认是否已安装插件;如果未安装,请双击开发包目录里的HCWebSDKPlugin.exe安装!";
message(str1, {
type: "warning"
});
}
);
},
});
setTimeout(() => {
let cw = Math.round(document.body.clientWidth / 1920);
let ch = Math.round(document.body.clientHeight / 1080);
let width = parseInt((hkvInfo.value.width * cw), 10);
let height = parseInt((hkvInfo.value.height * ch), 10);
if (height <= 200) {
height = 200;
}
if (height <= 200) {
height = 200;
}
let w1 = (window.innerWidth - document.getElementById(videoId.value).offsetLeft) - 1500;
let w2 = document.getElementById(videoId.value).clientHeight;
console.log('00000===>', width, height);
WebVideoCtrl.I_Resize(
width,
height
);
setVideoWindowResize(videoId.value, width, height);
clickLogin();
}, 2000);
}
// 根据设备宽高 和 windowchange 设置窗口大小
const setVideoWindowResize = (pid, width, height) => {
document.getElementById(pid).style.width = width + 'px';
document.getElementById(pid).style.height = height + 'px';
}
// 登录
const clickLogin = () => {
var szIP = hkvInfo.value.ip,
szPort = hkvInfo.value.port,
szUsername = hkvInfo.value.username,
szPassword = hkvInfo.value.password;
const iRet = WebVideoCtrl.I_Login(szIP, 1, szPort, szUsername, szPassword, {
timeout: 3000,
success: function (xmlDoc) {
setTimeout(function () {
setTimeout(function () {
getChannelInfo();
}, 1000);
getDevicePort();
}, 10);
},
error: function (err) {
console.log("登录-err===>", err);
},
});
if (iRet === -1) {
console.log(szIP +"_"+ szPort + " 已登录过!");
// 登录过直接进行预览
clickStartRealPlay();
}
}
const getDevicePort = () => {
var szDeviceIdentify = hkvInfo.value.ip;
if (null == szDeviceIdentify) {
return;
}
WebVideoCtrl.I_GetDevicePort(szDeviceIdentify).then((oPort) => {
console.log("获取端口", oPort);
});
}
//获取通道
const getChannelInfo = () => {
var szDeviceIdentify = hkvInfo.value.ip + '_' + hkvInfo.value.port;
if (null == szDeviceIdentify) {
return;
}
console.log('szDeviceIdentify==============>', szDeviceIdentify);
// 模拟通道
WebVideoCtrl.I_GetAnalogChannelInfo(szDeviceIdentify, {
success: function (xmlDoc) {
clickStartRealPlay();
},
error: function (oError) {
console.log(szDeviceIdentify + "模拟通道", oError.errorCode, oError.errorMsg);
}
});
// 数字通道
WebVideoCtrl.I_GetDigitalChannelInfo(szDeviceIdentify, {
success: function (xmlDoc) {
clickStartRealPlay();
},
error: function (oError) {
console.log(szDeviceIdentify + " 数字通道", oError.errorCode, oError.errorMsg);
}
});
}
// 开始预览
const clickStartRealPlay = (iStreamType) => {
var g_iWndIndex = 0;
var oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex) || null;
var szDeviceIdentify = hkvInfo.value.ip + '_' + hkvInfo.value.port,
iChannelID = 1,
bZeroChannel = false;
if ("undefined" === typeof iStreamType) {
iStreamType = 1;
}
if (null == szDeviceIdentify) {
return;
}
var startRealPlay = function () {
WebVideoCtrl.I_StartRealPlay(szDeviceIdentify, {
iStreamType: iStreamType,
iChannelID: iChannelID,
bZeroChannel: bZeroChannel,
success: function () {
WebVideoCtrl.I_Logout(szDeviceIdentify);
console.log(szDeviceIdentify, "开始预览!");
},
error: function (oError) {
console.log(szDeviceIdentify + "开始预览失败!");
},
});
};
//已经在播放了,先停止
if (oWndInfo != null) {
WebVideoCtrl.I_Stop({
success: function () {
startRealPlay();
}
});
} else {
startRealPlay();
}
}
// 停止预览
const clickStopRealPlay = () => {
WebVideoCtrl.I_Stop({
success: function () {
console.log("停止预览成功!");
},
error: function (oError) {
console.log("停止预览失败!");
},
});
}
//登出设备
const loginOut = () => {
const szDeviceIdentify = hkvInfo.value.ip + "_" + hkvInfo.value.port;
WebVideoCtrl.I_Logout(szDeviceIdentify);
}
//停止全部播放
const stopAllPlay = () => {
WebVideoCtrl.I_StopAllPlay();
}
//销毁插件
const breakDom = () => {
WebVideoCtrl.I_DestroyPlugin()
}
const viewReload = () => {
window.location.reload();
}
onMounted(() => {
});
onBeforeUnmount(() => {
loginOut();
stopAllPlay();
window.removeEventListener(viewReload());
});
onUnmounted(() => {
setTimeout(() => {
breakDom();
}, 100)
})
return {
loginOut,
stopAllPlay,
breakDom,
hkvInfo,
initS,
viewReload,
channels,
clickLogin,
clickStopRealPlay,
clickStartRealPlay,
setVideoWindowResize,
getChannelInfo,
getDevicePort,
...toRefs(state)
};
}
};
</script>
<style scoped lang="scss">
.video {
width: 100%;
height: 100%;
.plugin{
width: 100%!important;
height: 100%!important;
z-index: -100 !important;
//overflow-y: scroll;
}
}
</style>
父组件index.vue 引用 子组件
<template>
<div class="main-content" >
<div class="video-content"
v-loading="loading"
id="style-1"
element-loading-text="加载中..."
element-loading-svg-view-box="-10, -10, 50, 50"
element-loading-background="rgba(122, 122, 122, 0.8)"
ref="scrollContainer"
@wheel="handleScroll"
>
<div
v-for="(item, index) in cameraList"
:key="index"
class="canvas-contaniner"
:loading="loading"
>
<div class="videobox" v-if="item.status == 1">
<videoMonitorings :hkvInfo="item" class="video" :videoId="item.id" :key="index" />
</div>
<div v-else-if="item.status == 0" class="videobox">暂无...</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, onBeforeUnmount ,watch,computed} from "vue";
import { ElLoading } from 'element-plus'
import {
listApCamera,
} from "@/api/videoManage/videoConfiguration";
import { WebVideo } from "../../../../public/static/haiKangWeb3.0/webVideo.js";
import videoMonitorings from "./videoMonitorings.vue";
const loading = ref(false);
const pageNum = ref(1) // 当前页码
const pageSize = ref(4) // 每页数量
const total = ref(0);
//add
const scrollContainer = ref(null);
/*
* @以上hkList配置中 注意 loadingTime 和 id;其中loadingTime 建议和上一个时间间隔4S以上,id是动态加载生成填充的DOM树结构;
* 如果间隔时间不够 或DOM的ID一样 可能出现画面加载不出来、画面覆盖重叠等情况;通过配置这2个参数可以避免这样多个摄像头只需要 增加 hkList的配置项即可;
* */
//最终数据格格式
const dataListRef = ref([
{
ip: "", //IP地址
port: "", //端口号
username: "", //用户名
password: "", //密码
loadingTime: 1000, //间隔时长
status:1,
width: "828",
height: "385",
id: "divPlugin1",
},
{
ip: "", //IP地址
port: "", //端口号
username: "",
password: "",
loadingTime: 5000,
status:1,
width: "828",
height: "385",
id: "divPlugin2",
},
{
ip: "", //ip地址
port: "", //端口号
username: "",
password: "",
loadingTime: 9000,
status:1,
width: "828",
height: "385",
id: "divPlugin3",
},
{
ip: "", //IP地址
port: "", //端口号
username: "",
password: "",
loadingTime: 13000,
status:1,
width: "828",
height: "385",
id: "divPlugin4",
},
]);
const cameraList = ref([]);
//单个.
const dataList = ref({
hkvInfo01: {
ip: "", //IP地址
port: "", //端口号
rtspPort: "",
username: "",
password: "",
deviceport: "8000",
iChannelID: 1, //通道ID
loadingTime: "1000", //多视频窗口睡眠加载时长。同时多个加载会卡死或不显示
width: "808",
height: "377",
type: "camera01",
id: "divPlugin1"
},
hkvInfo02: {
ip: "", //IP地址
port: "", //端口号
rtspPort: "",
username: "",
password: "",
iChannelID: 1,
loadingTime: "5000",
width: "808",
height: "377",
type: "camera02",
id: "divPlugin2"
}
});
onMounted(async () => {
onSearch();
//监听滚动事件
window.addEventListener('scroll', handleScroll);
});
//滚动事件
function handleScroll(event) {
const container = document.querySelector('.video-content');
const { scrollTop, scrollHeight, clientHeight } = container;
if (scrollTop + clientHeight >= scrollHeight && !loading.value){
//根据屏幕高度来进行翻页,若没超过屏幕高度则不翻页) {
event.preventDefault(); // 阻止默认滚动行为
const deltaY = event.deltaY || event.detail || event.wheelDeltaY; // 获取垂直滚动距离
console.log('deltaY',deltaY)
//向上滚动
if (deltaY < 0 &&!loading.value) {
if(pageNum.value == 1 || pageNum.value == 0){
return false;
}
else if(pageNum.value>2){
pageNum.value = pageNum.value-1;
sessionStorage.setItem('pageNumber',pageNum.value-1);
onSearch()
}
}
//向下滚动
else if(deltaY >0 &&!loading.value){
sessionStorage.setItem('pageNumber', pageNum.value);
console.log('向下',pageNum.value)
onSearch()
}
}
}
async function onSearch() {
loading.value = true;
if(sessionStorage.getItem('pageNumber')){
pageNum.value = sessionStorage.getItem('pageNumber')
}
cameraList.value = [];
const { data } = await listApCamera({pageSize:pageSize.value, pageNum:pageNum.value});
total.value = data.total;
cameraList.value = [...data.list].map(item=>{
return{
ip: item.ip, //IP地址
port:item.port, //端口号
username:item.username,
password: item.password,
loadingTime: item.loadingTime,
status:item.status,
width: "828",
height: "385",
id: `divPlugin${item.id}`,
}
})
console.log(' cameraList.value=====>>>>>>',cameraList.value);
pageNum.value++
setTimeout(() => {
loading.value = false;
}, 500);
}
onBeforeUnmount(() => {
sessionStorage.setItem('pageNumber',1);
window.removeEventListener('scroll', handleScroll); //移除监听滚动事件
});
</script>
<style lang="scss" scoped>
.main-content {
margin: 10px 10px 0 !important;
overflow: auto;
}
//定义滚动条轨道 内阴影+圆角*/
#style-1::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 10px;
background-color: rgba(0, 0, 0, 0.52);
}
#style-1::-webkit-scrollbar
{
width: 12px;
background-color: #0F65E87C
}
#style-1::-webkit-scrollbar-thumb
{
border-radius: 20px;
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #555;
}
.video-content {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
position: relative;
width: 100%;
height: 85vh;
overflow-y: scroll; //需要添加
.canvas-contaniner {
width: 49.9%;
height: 49.9%;
//border: 1px solid red;
//padding: 10px;
position: relative;
display: flex;
justify-content: center;
align-items: center;
padding: 2px 1px;
overflow: hidden;
}
.videobox {
display: flex !important;
justify-content: center;
align-items: center !important;
width: 100% !important;
height: 100% !important;
font-size: 30px;
color: #fff;
position: relative !important;
background: black;
overflow: hidden;
.video {
width: 100% !important;
height: 100% !important;
object-fit: fill;
background-color: #000;
}
}
.loading {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
font-size: 30px;
color: #fff;
position: absolute;
background: black;
}
}
</style>
运行效果图如下:
//经过几天的踩坑,在这里分享给大家,希望对你们有所帮助!
//代码仅供参考,按需调整