Vue 3集成海康Web插件實現(xiàn)視頻監(jiān)控功能
引言
最近在項目中使用了 Vue 3 結(jié)合??礧eb插件來實現(xiàn)視頻監(jiān)控功能,過程中遇到了一些挑戰(zhàn)和解決方案。為了幫助開發(fā)小伙伴們更好地理解和應(yīng)用這一技術(shù)棧,特此分享一下我們的經(jīng)驗和代碼實現(xiàn)。
項目背景
在當前的項目中,我們需要實現(xiàn)一個視頻監(jiān)控系統(tǒng),能夠展示多個監(jiān)控點的實時視頻流,并支持用戶通過樹形結(jié)構(gòu)選擇不同的監(jiān)控點。為了實現(xiàn)這一需求,我們選擇了 Vue 3 作為前端框架,并集成了??礧eb插件來處理視頻流的播放和管理。
準備工作
1. 官網(wǎng)下載
在官網(wǎng)??甸_放平臺下載視頻web插件
2.安裝插件
3.插件js文件引入vue項目
將這3個js文件引入vue項目中的public
文件夾下新建文件夾放入
然后在index.html
文件中根路徑引入配置文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="icon" href="/favicon.ico" rel="external nofollow" > <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>前端青山</title> </head> <body> <div id="screen"></div> <!-- 連接內(nèi)網(wǎng)部署離線天地圖 --> <script src="/h5player/h5player.min.js"></script> <script src="/webControl/jquery-1.12.4.min.js"></script> <script src="/webControl/jsencrypt.min.js"></script> <script src="/webControl/web-control_1.2.5.min.js"></script> <script type="module" src="/src/main.ts"></script> <script src="/src/utils/d3/d3.js" charset="utf-8"></script> <script src="/src/utils/d3/D3SvgOverlay.js"></script> </body> </html>
最后我們開始構(gòu)建本次所需要調(diào)用的組件封裝
功能
子組件結(jié)構(gòu)
1. 模板部分
<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="videosp" ref="videosp"> <div id='corpvideo' ref="corpvideo"></div> </div> </div> </template>
<div class="play_windows">
: 主容器,包含視頻樹形結(jié)構(gòu)和視頻播放區(qū)域。<el-tree>
: Element Plus 的樹形組件,用于展示視頻監(jiān)控點的層級結(jié)構(gòu)。<div class="videosp">
: 視頻播放區(qū)域,包含一個id
為corpvideo
的div
,用于嵌入??礧eb插件。
2. 腳本部分
2.1 導(dǎo)入依賴
<script setup lang="ts"> 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";
ref
: Vue 3 的響應(yīng)式變量。onMounted
: 生命周期鉤子,組件掛載后執(zhí)行。nextTick
: 在 DOM 更新后執(zhí)行。defineProps
: 定義組件接收的屬性。defineEmits
: 定義組件觸發(fā)的事件。watch
: 監(jiān)聽數(shù)據(jù)變化。onBeforeUnmount
: 組件卸載前執(zhí)行。
2.2 定義屬性和事件
const emit = defineEmits(["handleSpjkPOIClick"]); const props = defineProps({ playURL: String, // 視頻url splitNum: Number, // 分屏播放,默認最大分屏4*4 dataTree: Object, // 樹 數(shù)據(jù) defaultProps: Object });
props
: 定義組件接收的屬性,包括playURL
、splitNum
、dataTree
和defaultProps
。emit
: 定義組件觸發(fā)的事件,如handleSpjkPOIClick
。
2.3 定義變量
let dataTree = ref<any>(props.dataTree); let defaultProps = ref<any>(props.defaultProps); let loading = ref<Boolean>(false); const corpvideo = ref<any>(); const videosp = ref<any>(null); let width: any = 0; let height: any = 0; let oWebControl: any = null; let initCount: any = 0; let pubKey: any = '';
dataTree
: 樹形結(jié)構(gòu)的數(shù)據(jù)。defaultProps
: 樹形組件的默認屬性。loading
: 加載狀態(tài)。corpvideo
: 視頻播放容器的引用。videosp
: 視頻播放區(qū)域的引用。width
和height
: 視頻播放區(qū)域的寬度和高度。oWebControl
: ??礧eb插件的實例。initCount
: 初始化計數(shù)器。pubKey
: RSA公鑰。
2.4 RSA加密
const setEncrypt = (value: any) => { let encrypt = new JSEncrypt(); encrypt.setPublicKey(pubKey); return encrypt.encrypt(value); }
setEncrypt
: 使用 JSEncrypt 庫進行 RSA 加密。
2.5 初始化插件
const initPlugin = () => { nextTick(() => { width = videosp.value.offsetWidth; height = videosp.value.offsetHeight; oWebControl = new webControl({ szPluginContainer: "corpvideo", iServicePortStart: 15900, iServicePortEnd: 15900, szClassId: "23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", cbConnectSuccess: function () { oWebControl.JS_StartService("window", { dllPath: "./VideoPluginConnect.dll" }).then(function () { oWebControl.JS_CreateWnd("corpvideo", width, height).then(function () { init(); }); }, function () {}); }, cbConnectError: function () { oWebControl = null; webControl.JS_WakeUp("VideoWebPlugin://"); initCount++; if (initCount < 3) { setTimeout(function () { initPlugin(); }, 3000); } else { console.log("插件啟動失敗,請檢查插件是否安裝!"); } }, cbConnectClose: function (bNormalClose: any) { oWebControl = null; webControl.JS_WakeUp("VideoWebPlugin://"); initCount++; if (initCount < 3) { setTimeout(function () { initPlugin(); }, 3000); } else { console.log("插件啟動失敗,請檢查插件是否安裝!"); } } }); }); }
initPlugin
: 創(chuàng)建??礧eb插件實例,并設(shè)置連接成功、連接失敗和連接關(guān)閉的回調(diào)函數(shù)。cbConnectSuccess
: 連接成功后啟動服務(wù)并創(chuàng)建視頻播放窗口。cbConnectError
: 連接失敗后嘗試重新連接。cbConnectClose
: 連接關(guān)閉后嘗試重新連接。
2.6 獲取公鑰
const getPubKey = (callback: any) => { oWebControl.JS_RequestInterface({ funcName: "funcName", argument: JSON.stringify({ keyLength: 1024 }) }).then((oData: any) => { if (oData.responseMsg.data) { pubKey = oData.responseMsg.data; callback(); } }); }
getPubKey
: 請求公鑰并調(diào)用回調(diào)函數(shù)。
2.7 初始化視頻播放
const init = () => { getPubKey(() => { appkey = "appkey "; secret = setEncrypt("secret"); ip = "ip "; playMode = 0; port = 443; snapDir = "D:\\SnapDir"; videoDir = "D:\\VideoDir"; layout = "1x1"; enableHTTPS = 1; encryptedFields = 'secret'; showToolbar = 1; showSmart = 1; buttonIDs = "0,16,256,257,258,259,260,512,513,514,515,516,517,768,769"; oWebControl.JS_RequestInterface({ funcName: "init", argument: JSON.stringify({ appkey: appkey, secret: secret, ip: ip, playMode: playMode, port: port, snapDir: snapDir, videoDir: videoDir, layout: layout, enableHTTPS: enableHTTPS, encryptedFields: encryptedFields, showToolbar: showToolbar, showSmart: showSmart, buttonIDs: buttonIDs }) }).then((oData: any) => { oWebControl.JS_Resize(width, height); }); }); }
init
: 使用公鑰加密敏感信息,并請求初始化視頻播放。
2.8 播放視頻
const JSRequestInterface = (code: any) => { cameraIndexCode = code.replace(/(^\s*)/g, "").replace(/(\s*$)/g, ""); oWebControl.JS_RequestInterface({ funcName: "startPreview", argument: JSON.stringify({ cameraIndexCode: cameraIndexCode, streamMode: streamMode, transMode: transMode, gpuMode: gpuMode, wndId: wndId }) }); }
JSRequestInterface
: 請求播放指定監(jiān)控點的視頻。
2.9 隱藏和顯示窗口
const JSHideWnd = () => { oWebControl.JS_HideWnd(); oWebControl.JS_DestroyWnd().then(function () {}, function () {}); } const JSShowWnd = () => { initPlugin(); oWebControl.JS_ShowWnd(); }
JSHideWnd
: 隱藏并銷毀視頻播放窗口。JSShowWnd
: 重新初始化并顯示視頻播放窗口。
2.10 監(jiān)聽窗口關(guān)閉和調(diào)整大小
window.addEventListener('unload', JSHideWnd); const getElementPosition = () => { width = window.innerWidth * 0.3; height = window.innerHeight * 0.56; oWebControl.JS_Resize(width, height); }; window.addEventListener('resize', getElementPosition);
window.addEventListener('unload', JSHideWnd)
: 監(jiān)聽窗口關(guān)閉事件,隱藏并銷毀視頻播放窗口。getElementPosition
: 獲取窗口大小并調(diào)整視頻播放窗口的尺寸。window.addEventListener('resize', getElementPosition)
: 監(jiān)聽窗口調(diào)整大小事件,動態(tài)調(diào)整視頻播放窗口的尺寸。
2.11 處理節(jié)點點擊事件
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 = res.data.rows.map((child: any) => ({ ...child, name: child.equipmentName, })); res.data.rows.forEach((child: any) => { e.children.push(child); }); (e as any).expanded = true; } }); } } const videoUrl = (equipmentCoding: string) => { let params = { equipmentCoding: equipmentCoding, }; JSRequestInterface(equipmentCoding) }
pitchOns
: 處理樹形節(jié)點點擊事件,根據(jù)節(jié)點類型調(diào)用相應(yīng)的方法。handleAddChild
: 處理節(jié)點的子節(jié)點加載,請求子節(jié)點數(shù)據(jù)并展開節(jié)點。videoUrl
: 請求指定監(jiān)控點的視頻URL并播放視頻。
2.12 暴露方法
defineExpose({ initPlugin, JSHideWnd, JSShowWnd, JSRequestInterface })
defineExpose
: 暴露組件的方法,供外部調(diào)用。
3. 樣式部分
<style scoped lang="scss"> // 公共element樣式 @import '@/styles/eleCustomize.scss'; /* 樣式 */ .play_windows { display: flex; width: 100% !important; .tree-form { width: 18vw; height: 28vw; overflow: auto; padding: 0; } } .videosp { width: 32vw; height: 60vh !important; #corpvideo { width: 100% !important; height: 100% !important; margin-top: 0.5vh; } #player-container-0 { width: 100% !important; height: 100% !important; } } /* 屏幕寬度超過1920px時應(yīng)用 */ @media (min-width: 8000px) { .play_windows { .tree-form { width: 10vw; height: 18vw; } } .videosp { width: 45vw; } } ::v-deep(.el-radio-button__inner) { width: 2vw; height: 1vw; display: flex; justify-content: center; align-items: center; font-size: 0.6vw; } .video-button { width: 3vw; height: 1vw; display: flex; justify-content: center; align-items: center; font-size: 0.6vw; } ::v-deep(.el-radio-button__inner) { background: transparent !important; color: white !important; border: 0 !important; display: flex; align-items: center; height: 3.5vh !important; color: white !important; margin: 0.2vw; font-size: 1.6vh !important; background: transparent !important; border: 0.1vw solid #009392 !important; border-radius: 0.2vw !important; } ::v-deep(.el-radio-button__original-radio:checked + .el-radio-button__inner) { background: linear-gradient(90deg, rgba(0, 96, 204, 0.2) 0%, rgba(0, 165, 189, 0.6) 100%) !important; color: white !important; border-color: none !important; } </style>
子組件 ScreenMonitoring
主要實現(xiàn)了監(jiān)控點的樹形結(jié)構(gòu)展示和視頻播放控制。通過 el-tree
組件展示監(jiān)控點的樹形結(jié)構(gòu),并在節(jié)點被點擊時調(diào)用視頻播放插件的初始化和播放方法。子組件提供了 JSRequestInterface
方法請求視頻流,initialize
方法初始化視頻播放,以及 JSHideWnd
方法停止視頻播放,確保視頻監(jiān)控功能的完整性和可控性。
父組件調(diào)用
1. 模板部分
<template> <screenVideoDialog v-model="dialogVideo" title="公安監(jiān)控" width="55%" @close="onCloseDialog" @open="onOpenDialog" :draggable="false" > <div class="my_dialog_slot" style="height:60vh;" v-if="dialogVideo"> <ScreenMonitoring ref="screenmonitoring" :dataTree="dataTree" :defaultProps="defaultProps" @handleSpjkPOIClick="handleSpjkPOIClick" /> </div> </screenVideoDialog> </template>
<screenVideoDialog>
: 這是一個自定義的對話框組件,用于顯示視頻監(jiān)控內(nèi)容。通過v-model
綁定dialogVideo
變量來控制對話框的顯示和隱藏。@close="onCloseDialog"
: 當對話框關(guān)閉時,調(diào)用onCloseDialog
方法。@open="onOpenDialog"
: 當對話框打開時,調(diào)用onOpenDialog
方法。<div class="my_dialog_slot">
: 包含ScreenMonitoring
子組件的容器,設(shè)置高度為60vh
,并使用v-if
指令確保只有在dialogVideo
為true
時才渲染。<ScreenMonitoring>
: 子組件,用于顯示視頻監(jiān)控內(nèi)容。通過ref
綁定screenmonitoring
變量,以便在父組件中調(diào)用子組件的方法。傳遞dataTree
和defaultProps
屬性,并監(jiān)聽handleSpjkPOIClick
事件。
2. 腳本部分
<script setup lang="ts"> import { ref } from 'vue'; import screenVideoDialog from '@/components/Dialog/screenVideoDialog.vue'; import ScreenMonitoring from '@/components/Dialog/screenMonitoring.vue'; const dialogVideo = ref(false); const dataTree = ref([ // 樹形結(jié)構(gòu)數(shù)據(jù) ]); const defaultProps = ref({ children: 'children', label: 'label' }); const screenmonitoring = ref<InstanceType<typeof ScreenMonitoring> | null>(null); // 處理監(jiān)控點點擊事件 const handleSpjkPOIClick = (poiId: string, coord: string) => { let params = { UnitIndexCode: poiId }; screenmonitoring.value?.JSRequestInterface(poiId); // getGetByCodes(params).then(res => { // setTimeout(() => { // screenmonitoring.value?.initialize(res.data.urls[0], res.data.urls); // }, 1000); // }); }; // 關(guān)閉對話框時停止視頻 const onCloseDialog = (e: any) => { screenmonitoring.value?.JSHideWnd(); }; // 打開對話框時初始化視頻 const onOpenDialog = (e: any) => { screenmonitoring.value?.initPlugin(); }; </script>
dialogVideo
: 一個響應(yīng)式變量,用于控制對話框的顯示和隱藏。dataTree
: 樹形結(jié)構(gòu)的數(shù)據(jù),用于傳遞給ScreenMonitoring
子組件。defaultProps
: 樹形組件的默認屬性,用于傳遞給ScreenMonitoring
子組件。screenmonitoring
: 一個響應(yīng)式變量,用于存儲ScreenMonitoring
子組件的實例,以便在父組件中調(diào)用其方法。handleSpjkPOIClick
: 處理監(jiān)控點點擊事件的方法。當用戶點擊某個監(jiān)控點時,會調(diào)用子組件的JSRequestInterface
方法,并傳遞poiId
參數(shù)。注釋掉的部分是獲取視頻 URL 的邏輯,可以根據(jù)實際需求啟用。onCloseDialog
: 當對話框關(guān)閉時調(diào)用的方法。調(diào)用子組件的JSHideWnd
方法,停止視頻播放。onOpenDialog
: 當對話框打開時調(diào)用的方法。調(diào)用子組件的initPlugin
方法,初始化視頻播放。
3. 樣式部分
<style scoped> .my_dialog_slot { display: flex; justify-content: center; align-items: center; height: 100%; } </style>
.my_dialog_slot
: 設(shè)置對話框內(nèi)容的樣式,確保內(nèi)容居中顯示。
通過上述代碼,我們在父組件中實現(xiàn)了視頻監(jiān)控對話框的顯示和隱藏,并在對話框打開和關(guān)閉時調(diào)用子組件的相應(yīng)方法,以控制視頻的播放和停止。
本文詳細介紹了如何使用 Vue 3 框架集成海康Web插件實現(xiàn)視頻監(jiān)控功能。通過定義屬性、事件、變量,以及編寫初始化、播放視頻、處理節(jié)點點擊事件等方法,我們成功實現(xiàn)了視頻監(jiān)控系統(tǒng)的前端部分。同時,通過樣式部分的定制,確保了良好的用戶體驗。希望本文對讀者在開發(fā)類似項目時有所幫助。
到此這篇關(guān)于Vue 3集成??礧eb插件實現(xiàn)視頻監(jiān)控的文章就介紹到這了,更多相關(guān)Vue??礧eb插件視頻監(jiān)控內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用vis-timeline繪制甘特圖并實現(xiàn)時間軸的中文化(案例代碼)
這篇文章主要介紹了使用vis-timeline繪制甘特圖并實現(xiàn)時間軸的中文化(案例代碼),本文結(jié)合實例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-02-02Vue使用$attrs實現(xiàn)爺爺直接向?qū)O組件傳遞數(shù)據(jù)
這篇文章主要為大家詳細介紹了Vue如何使用$attrs實現(xiàn)爺爺直接向?qū)O組件傳遞數(shù)據(jù),文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2024-02-02