Vue3 中集成海康 H5 监控视频播放功能

news2024/9/25 11:22:40

​🌈个人主页:前端青山
🔥系列专栏:Vue篇
🔖人终将被年少不可得之物困其一生

依旧青山,本期给大家带来Vuet篇专栏内容:Vue-集成海康 H5 监控视频播放功能

目录

一、引言

二、环境搭建

三、代码解析

子组件部分

1. 导入模块和组件

2. 定义组件属性和事件

3. 初始化变量

4. 初始化视频插件

5. 控制分屏数量

6. 视频线路弹框按钮

7. 生命周期钩子

8. 初始化视频播放

9. 处理事件

10.调用插件播放

父组件调用

一、引言

随着视频监控技术的发展,许多应用场景需要集成实时视频监控功能。本文将详细介绍如何在 Vue 3 应用中集成海康 H5 监控视频播放功能,实现视频的实时播放、分屏显示以及全屏切换等功能。

二、环境搭建

为了确保代码能够正常运行,我们需要准备以下开发环境:

  • Vue 3:用于构建前端应用。

  • Element Plus:用于 UI 组件库。

  • 海康 H5 SDK:用于播放视频流。

三、代码解析

子组件部分

<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>
  • 功能说明

    • play_windows 容器:包含两个主要部分,左侧为树形结构,右侧为视频播放区域。

    • el-tree 组件:展示监控设备树形结构,点击节点触发 pitchOns 方法。

    • 视频播放区域:通过按钮控制不同的分屏模式(1×1、3×3、4×4)及全屏模式。

    • id='corpvideo':指定视频播放容器的 ID,供 H5 SDK 使用。

1. 导入模块和组件
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';
  • 功能说明:导入了 Vue 的一些核心函数,如 refonMountednextTick 等,以及 Element Plus 的消息提示组件 ElMessage 和相关 API。

2. 定义组件属性和事件
const emit = defineEmits(["handleSpjkPOIClick"]);
const props = defineProps({
  playURL: String, // 视频 URL
  splitNum: Number, // 分屏播放,默认最大分屏 4*4
  dataTree: Object, // 树形数据
  defaultProps: Object
});
  • 功能说明:定义了组件的属性 props 和自定义事件 emit,用于接收父组件传递的数据和触发事件。

3. 初始化变量
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;
  • 功能说明:定义了一些响应式变量,用于存储数据和状态,如 loading 用于控制加载状态,myPlugin 用于存储视频插件实例。

4. 初始化视频插件
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,
  });
};
  • 功能说明:定义了一个方法 myPlugins,用于初始化视频插件实例,并配置相关参数。

5. 控制分屏数量
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;
};
  • 功能说明:定义了一个方法 playBackNum,用于控制分屏数量,并支持全屏显示。

6. 视频线路弹框按钮
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, '监控视频的值');
};
  • 功能说明:定义了一个方法 videoTabClick,用于控制视频线路弹框按钮,并根据不同的类型调整分屏数量和播放视频。

7. 生命周期钩子
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('切换了');
});
  • 功能说明:在组件挂载时初始化视频插件,并绑定事件回调。在组件卸载前执行清理操作。

8. 初始化视频播放
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('监控视频异常'); // 失败操作
    }
  );
};
  • 功能说明:定义了一个方法 initialize,用于初始化视频播放,并处理加载状态和错误提示。

9. 处理事件
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;
            }
          })
        }
}
10.调用插件播放
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>
  1. 初始化数据树

    • dataTreedataTree1 是两个响应式数组,用于存储处理后的数据。

    • screenmonitoring 是一个引用,用于指向 ScreenMonitoring 子组件的实例。

    • defaultProps 是传递给子组件的默认属性配置。

  2. 组件挂载时

    • nextTick():等待 DOM 更新完成后再执行后续操作。

    • getTreeJson(params):从服务器获取数据,并处理返回的数据。

    • extractNameAndRebuildTree(item):递归处理每个节点,提取 name 并放在最外层。

  3. 处理点击事件

    • handleSpjkPOIClick(poiId, coord):当点击某个 时,获取对应的视频 URL 并初始化视频播放。

    • getGetByCodes(params):从服务器获取视频 URL 数据。

    • setTimeout(() => { ... }, 1):延迟 1 毫秒后初始化视频播放。

通过这种方式,父组件能够有效地初始化数据树,并在点击 树状 时触发视频播放。

本文旨在详细介绍如何在 Vue 3 应用中集成海康 H5 监控视频播放功能,实现视频的实时播放、分屏显示以及全屏切换等功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2163412.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring项目报错:Public Key Retrieval is not allowed

报错原因&#xff1a; 如图 在你项目的数据库下可以找到该文件 解决方案&#xff1a; 在service-oa模块的application-dev.yml文件中 在红框中改成下面代码&#xff0c;数据库与具体项目保持一致&#xff0c;不一定是我这个&#xff0c;改allowPublicKeyRetrievaltrue String…

支持K歌音箱方案应用的高性能 32 位蓝牙音频应用处理器-BP1048B2

DSP是一类嵌入式通用可编程微处理器&#xff0c;主要用于实现对信号的采集、识别、变换、增强、控制等算法处理&#xff0c;是各类嵌入式系统的“大脑”应用十分广泛。BP1048B2是一款高性能DSP音频数字信号处理器芯片&#xff0c;能实现多种音频功能如混响、均衡、滤波、反馈抑…

Python邮件发送附件:怎么配置SMTP服务器?

Python邮件发送附件如何实现&#xff1f;Python发送带附件邮件&#xff1f; 在自动化和脚本编写中&#xff0c;使用Python发送带有附件的邮件是一个非常实用的功能。AokSend将详细介绍如何配置SMTP服务器&#xff0c;以便在Python中实现邮件发送附件的功能。 Python邮件发送附…

Postman/Jmeter接口测试

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、什么是接口测试 通常做的接口测试指的是系统对外的接口&#xff0c;比如你需要从别的系统来获取到或者同步资源与信息&#xff0c;他们会提供给你一个写好…

独立站烧钱背后:Facebook 广告转化率策略的神秘“致胜法则”

Facebook广告作为大部分零售独立站的主要“烧钱”渠道&#xff0c;投放策略的决策往往比日常操作技巧更为重要。 之前出海笔记分享过关于在我们烧了一年广告预算后&#xff0c;对人群定位的总结 这次在另外一个项目上再次印证了我们的推断。 省流&#xff1a;直接告诉你们结论…

全国糖酒会全域采购商选品会前瞻-见证零售新势力的崛起与变革

消费市场正经历着前所未有的变革。新兴零售渠道如雨后春笋般迅速崛起&#xff0c;对传统大卖场和电商模式提出了严峻挑战。在这一变革浪潮中&#xff0c;仓储会员店、零食折扣店、即时零售、内容电商以及私域团购等新兴模式脱颖而出&#xff0c;零售商与供应商关系被重构&#…

2024最新Linux发行版,Kali Linux迎来劲敌,零基础入门到精通,收藏这一篇就够了

概念简介 Parrot OS 是一款基于 Debian 的 Linux 发行版&#xff0c;专门为安全研究、渗透测试、开发以及隐私保护而设计。由 Frozenbox 团队开发的 Parrot OS&#xff0c;结合了现代安全工具、用户友好的环境以及出色的隐私保护特性&#xff0c;成为网络安全从业者、开发人员…

EasyExcel 多个不同对象集合,导入同一个sheet中

需求&#xff1a;将两块数据&#xff0c;写入要一个excel里面。 根据项目&#xff0c;导入依赖版本 <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.0.5</version> <…

旷视 ShuffleNetV2

目录 前言 一、ShuffleNetV2带来的创新点四条轻量化网络设计原则 1.1 准则一&#xff1a;相同的输入输出通道数能够减少内存访问成本(MAC) 1.2 准则二: 过多的分组卷积会增加 MAC 1.3 准则三: 网络的碎片化程度会减少并行化程度&#xff08;碎片化操作对并行加速不友好&am…

用计算器学习float、输入输出函数的格式化

上一篇介绍了C语言的一部分基础知识&#xff0c;今天我们来继续深入一点讲。 引入浮点数——float 做一个加减法计算器显然不能满足其他计算需求&#xff0c;比如我们生活中的东西并不总是用整数来衡量。我们有五毛钱&#xff0c;有半杯水&#xff0c;有随时都在变的速度&…

大模型面试百问百答

大家好&#xff0c;这里是 大模型八哥。今天分享大模型面试相关知识点&#xff0c;持续更新。 1. RAG技术体系的总体思路 数据预处理->分块&#xff08;这一步骤很关键&#xff0c;有时候也决定了模型的效果&#xff09;->文本向量化->query向量化->向量检索->重…

钰泰-ETA6964A 锂电池充电器IC

描述. ETA6964A 是一款高度集成的 3A 开关模式电池充电管理和系统电源路径管理器件&#xff0c;适用于单节锂离子和锂聚合物电池。它具有快速充电功能&#xff0c;支持高输入电压&#xff0c;适用于各种智能手机、平板电脑和便携式设备。其低阻抗电源路径优化了开关模式的运行…

第六次人口普查,人口前100姓氏

第六次人口普查中&#xff0c;人口前100的姓氏具体排名和分布情况如下&#xff1a; 人口前10的姓氏 李&#xff1a;约占全国汉族人口的7.94%&#xff0c;是人口最多的姓氏。 王&#xff1a;约占汉族人口的7.41%&#xff0c;仅次于李姓。 张&#xff1a;约占全国汉族人口总数的7…

视频汇聚/视频存储/安防视频监控EasyCVR平台RTMP推流显示离线是什么原因?

视频汇聚/视频存储/安防视频监控EasyCVR视频汇聚平台兼容性强、支持灵活拓展&#xff0c;平台可提供视频远程监控、录像、存储与回放、视频转码、视频快照、告警、云台控制、语音对讲、平台级联等视频能力。 EasyCVR安防监控视频综合管理平台采用先进的网络传输技术&#xff0…

Goland的使用

一、安装Goland 一、Goland简介 Goland是由JetBrains公司旨在为go开发者提供的一个符合人体工程学的新的商业IDE。这个IDE整合了IntelliJ平台的有关go语言的编码辅助功能和工具集成特点 二、下载相应的安装包 1、官网下载地址 GoLand by JetBrains: More than just a Go IDE 三…

网络编程,端口号,网络字节序,udp

前面一篇我们讲了网络的基础&#xff0c;网络协议栈是什么样的&#xff0c;数据如何流动传输的&#xff1b;接下来这篇&#xff0c;我们将进行实践操作&#xff0c;真正的让数据跨网络进行传输&#xff1b; 1.网络编程储备知识 1.1 初步认识网络编程 首先我们需要知道我们的…

Facebook对现代社交互动的影响

自2004年成立以来&#xff0c;Facebook已经成为全球最大的社交媒体平台之一&#xff0c;改变了人们的交流方式和社交互动模式。作为一个数字平台&#xff0c;Facebook不仅为用户提供了分享生活点滴的空间&#xff0c;也深刻影响了现代社交互动的各个方面。本文将探讨Facebook如…

Ollama在Windows安装,使用,简单调用API

一、安装ollama 1、安装 在Windows本地安装ollama&#xff0c;官方网页&#xff1a;https://ollama.com/download/windows 下载完安装包&#xff0c;安装就好&#xff0c;默认应该是C盘。应该是没办法改&#xff0c;如果有小伙伴能改&#xff0c;也请告知一下。 2、验证安装…

华为OD机试 - 数据单元的变量替换 - 分治、递归(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

基于yolov8+deepsort+gradio实现目标追踪演示

【效果展示】 【测试环境】 ultralytics8.2.95 gradio4.26.0 torch1.9.0cu111 理论上支持最新ultralytics版本 【实现部分代码】 with gr.Blocks() as demo:with gr.Tab("追踪"):# 使用Markdown显示文本信息&#xff0c;介绍界面的功能gr.Markdown(""…