随着视频监控技术的发展,许多应用场景需要集成实时视频监控功能。本文将详细介绍如何在 Vue 3 应用中集成海康 H5 监控视频播放功能,实现视频的实时播放、分屏显示以及全屏切换等功能。
为了确保代码能够正常运行,我们需要准备以下开发环境:
- <template>
- <div class="play_windows" v-loading="loading" element-loading-background="rgba(122, 122, 122, 0.8)">
- <div class="tree-form">
- <el-tree
- ref="tree"
- :data="dataTree"
- :props="defaultProps"
- :highlight-current="true"
- @node-click="pitchOns"
- >
- <template #default="{ node, data }">
- <span class="custom-tree-node">
- {{ data.name }}
- </span>
- </template>
- </el-tree>
- </div>
- <div class="video">
- <div class="dialog-slot-video-header-right">
- <el-button class="myButton" :class="{ 'active': videoIndex == 4 }" @click="videoTabClick(4)">1×1</el-button>
- <el-button class="myButton" :class="{ 'active': videoIndex == 1 }" @click="videoTabClick(1)">3×3</el-button>
- <el-button class="myButton" :class="{ 'active': videoIndex == 2 }" @click="videoTabClick(2)">4×4</el-button>
- <el-button class="myButton" :class="{ 'active': videoIndex == 3 }" @click="videoTabClick(3)">整体全屏</el-button>
- </div>
- <div id='corpvideo'></div>
- </div>
- </div>
- </template>
- import { ref, onMounted, nextTick, defineProps, defineExpose, defineEmits, watch, onBeforeUnmount } from 'vue';
- import { ElMessage } from 'element-plus';
- import { videoallList } from '@/api/screenVideo/index';
- import { getGetByCode } from '@/api/videoSurveillance/index';
- const emit = defineEmits(["handleSpjkPOIClick"]);
- const props = defineProps({
- playURL: String, // 视频 URL
- splitNum: Number, // 分屏播放,默认最大分屏 4*4
- dataTree: Object, // 树形数据
- defaultProps: Object
- });
- let dataTree = ref<any>(props.dataTree);
- let defaultProps = ref<any>(props.defaultProps);
- let loading = ref<Boolean>(false);
- let myPlugin = ref<any>(null);
- let index = ref<any>(1); // 多屏播放显示第几个
- let mode = ref<any>(1); // 0 为低级播放,1 为高级播放
- const urlList = ref<any>([]);
- let playURLs = ref<any>("");
- const jsPlugin = (window as any).JSPlugin;
- const myPlugins = () => {
- myPlugin.value = new jsPlugin({
- szId: 'corpvideo', // 需要英文字母开头,唯一性,必填
- szBasePath: '/h5player', // 必填,与 h5player.min.js 的引用目录一致
- bSupporDoubleClickFull: true, // 是否支持双击全屏,默认 true
- iMaxSplit: 4, // 分屏播放,默认最大分屏 4*4
- iCurrentSplit: splitNum.value,
- oStyle: {
- borderSelect: '#FFCC00',
- },
- openDebug: true,
- });
- };
- const tabPosition = ref<any>(1);
- const playBackNum = (num: any) => {
- if (num == "3") {
- myPlugin.value.JS_FullScreenDisplay(true).then(
- () => { console.log(`wholeFullScreen success`) },
- (e: any) => { console.error(e) }
- );
- return;
- }
- if (num == splitNum.value) {
- return;
- }
- splitNum.value = num;
- };
- const splitNum = ref<any>(1);
- const videoIndex = ref<number>(4); // 视频信息弹框默认值 index
- const videoTabClick = (type: number) => {
- videoIndex.value = Number(type);
- if (type == 1) {
- splitNum.value = 3;
- const totalWindows = splitNum.value * splitNum.value;
- for (let i = 0; i < totalWindows; i++) {
- const url = urlList.value[i] || urlList.value[0];
- myPlugin.value.JS_Play(url, { playURL: url, mode: mode.value }, i).then(
- () => console.log(`Playing in window ${i}`),
- (e: any) => console.error('Error playing video', e)
- );
- }
- } else if (type == 2) {
- splitNum.value = 4;
- const totalWindows = splitNum.value * splitNum.value;
- for (let i = 0; i < totalWindows; i++) {
- const url = urlList.value[i] || urlList.value[0];
- myPlugin.value.JS_Play(url, { playURL: url, mode: mode.value }, i).then(
- () => console.log(`Playing in window ${i}`),
- (e: any) => console.error('Error playing video', e)
- );
- }
- } else if (type == 3) {
- myPlugin.value.JS_FullScreenDisplay(true).then(
- () => { console.log(`wholeFullScreen success`) },
- (e: any) => { console.error(e) }
- );
- return;
- } else if (type == 4) {
- splitNum.value = 1;
- }
- myPlugin.value.JS_ArrangeWindow(splitNum.value).then(
- () => { console.log(`arrangeWindow to ${splitNum.value}x${splitNum.value} success`) },
- (e: any) => { console.error(e) }
- );
- console.log(splitNum.value, '监控视频的值');
- };
- onMounted(() => {
- nextTick(() => {
- myPlugins();
- // 事件回调绑定
- myPlugin.value.JS_SetWindowControlCallback({
- windowEventSelect: function (iWndIndex: any) { // 插件选中窗口回调
- console.log('windowSelect callback: ', iWndIndex);
- },
- pluginErrorHandler: function (iWndIndex: any, iErrorCode: any, oError: any) { // 插件错误回调
- console.log('pluginError callback: ', iWndIndex, iErrorCode, oError);
- },
- windowEventOver: function (iWndIndex: any) { // 鼠标移过回调
- // console.log(iWndIndex);
- },
- windowEventOut: function (iWndIndex: any) { // 鼠标移出回调
- // console.log(iWndIndex);
- },
- windowEventUp: function (iWndIndex: any) { // 鼠标mouseup事件回调
- // console.log(iWndIndex);
- },
- windowFullCreenChange: function (bFull: any) { // 全屏切换回调
- console.log('fullScreen callback: ', bFull);
- },
- firstFrameDisplay: function (iWndIndex: any, iWidth: any, iHeight: any) { // 首帧显示回调
- console.log('firstFrame loaded callback: ', iWndIndex, iWidth, iHeight);
- },
- performanceLack: function () { // 性能不足回调
- console.log('performanceLack callback: ');
- }
- });
- });
- });
-
- onBeforeUnmount(() => {
- console.log('切换了');
- });
- const initialize = (playURL: any, urls?: any[]) => {
- urlList.value = urls;
- playURLs.value = playURL;
- loading.value = true;
- index.value = myPlugin.value.currentWindowIndex;
- myPlugin.value.JS_Play(playURL, { playURL, mode: mode.value }, index.value).then(
- () => { loading.value = false }, // 成功操作
- (e: any) => {
- loading.value = false;
- ElMessage.error('监控视频异常'); // 失败操作
- }
- );
- };
- const pitchOns = (e: any) => {
- if (!e || !e.self) {
- if (e.equipmentCoding) {
- handleAddChild(e);
- }
- return;
- }
- if (e.children) {
- emit("handleSpjkPOIClick", e.self.indexCode, '');
- return;
- } else {
- handleAddChild(e);
- }
- };
-
- const handleAddChild = (e: any) => {
- if (!e || !e.self) {
- if (e.equipmentCoding) {
- videoUrl(e.equipmentCoding);
- }
- return;
- }
- if (e.self.indexCode) {
- let params = {
- UnitIndexCode: e.self.indexCode,
- };
- videoallList(params).then((res: any) => {
- if (res.data.rows.length == 0) {
- emit("handleSpjkPOIClick", e.self.indexCode, '');
- } else {
- e.children = e.children || [];
- // 修改 res.data.rows 中所有数据对象的字段 equipmentName 变成 name
- res.data.rows = res.data.rows.map((child: any) => ({
- ...child,
- name: child.equipmentName, // 将 equipmentName 字段复制到 name 字段
- // 删除原 equipmentName 字段
- }));
- res.data.rows.forEach((child: any) => {
- e.children.push(child);
- });
- // 展开当前节点
- (e as any).expanded = true;
- }
- })
- }
- }
- const videoUrl =(e:any)=>{
- let params = {
- equipmentCoding: e,
- };
- getGetByCode(params).then(res => {
- setTimeout(() => {
- initialize(res.data.url);
- }, 1);
- });
- }
- // 使用 watch 监听 splitNum 的变化
- watch(splitNum, (newValue, oldValue) => {
- if (newValue !== oldValue) {
- myPlugins();
- myPlugin.value.JS_ArrangeWindow(splitNum.value).then(
- () => { console.log(`arrangeWindow to ${splitNum.value}x${splitNum.value} success`) },
- (e: any) => { console.error(e) }
- )
- }
- });
- //最后暴露方法
- defineExpose({
- initialize,
- myPlugins
- })
- <template>
- <div>
- <ScreenMonitoring ref="screenmonitoring" :dataTree="dataTree" :defaultProps="defaultProps" @handleSpjkPOIClick="handleSpjkPOIClick" />
- </div>
- </template>
-
- <script setup>
- import { ref, onMounted, nextTick } from 'vue';
-
- const dataTree = ref<any>([]);
- const dataTree1 = ref<any>([]);
- let screenmonitoring = ref();
- const defaultProps = {
- children: 'children',
- label: 'name',
- };
-
- onMounted(() => {
- nextTick(() => {
- let params = {};
- getTreeJson(params).then((res: any) => {
- let list = res.rows[0].children[9].children;
-
- list.forEach((item: any) => {
- extractNameAndRebuildTree(item); // 对每个根节点执行递归提取
- });
-
- dataTree.value = list; // 将处理后的列表赋值给 dataTree
- });
- });
- });
-
- const extractNameAndRebuildTree = (node: any) => {
- // 如果节点有 self,提取 name 并放在最外层
- if (node.self && node.self.name) {
- node.name = node.self.name;
- }
- // 如果节点有 children,递归处理每个子节点
- if (node.children && node.children.length > 0) {
- node.children.forEach((child: any) => {
- extractNameAndRebuildTree(child);
- });
- }
- };
- const handleSpjkPOIClick = (poiId: string, coord: string) => {
- let params = {
- UnitIndexCode: poiId,
- };
- getGetByCodes(params).then((res: any) => {
- setTimeout(() => {
- screenmonitoring.value.initialize(res.data.urls[0], res.data.urls);
- }, 1);
- });
- };
- </script>
通过这种方式,父组件能够有效地初始化数据树,并在点击 树状 时触发视频播放。
本文旨在详细介绍如何在 Vue 3 应用中集成海康 H5 监控视频播放功能,实现视频的实时播放、分屏显示以及全屏切换等功能。