IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 使用VUE+Element + webSocket +videojs + HLS 直播功能 -> 正文阅读

[网络协议]使用VUE+Element + webSocket +videojs + HLS 直播功能

使用VUE+Element + webSocket +videojs + HLS 直播功能

祝点赞收藏转发的小伙伴 原神 2.2 胡桃公子必不歪 。:.゚ヽ(。???。)ノ゚.:。+゚

文章目录

先说方法 (因为我是两个demo,所以就分开写了,不过大体的逻辑一样,复制粘贴改改就行)

方法1:

使用websocket连接后端返回返回直播流,然后前端使用videojs接收(会有延迟)

方法2:

使用websoclet连接后端返回一张一张的图片,然后不停换图片以达到视频的效果(不会有延迟)

效果图 1 对应方法1的 视频展示方法

在这里插入图片描述
效果图2,对应方法2的 图片展示方法
在这里插入图片描述

重难点分析


方法一:使用websocket连接后端返回返回直播流(我的是hls流 然后hls还分H.265和H.264,这个视频方法只支持H.264的,H.265请用图片方式),然后前端使用videojs接收

重点:安装插件

package.json添加插件

 {"video.js": "^7.11.8","videojs-contrib-hls": "^5.15.0",}

然后项目重新npm i
main.js 添加


// video 组件
import Videojs from 'video.js'
import 'video.js/dist/video-js.css'
Vue.prototype.$video = Videojs
import hls from 'videojs-contrib-hls';
Vue.use(hls); // 要播放hls流, 这哥们就要上场


难点分析

难点1. 分屏功能(一般是1屏,4屏,9屏)

难点2. websocket的循环创建以及关闭的时候的销毁

难点3. videojs的销毁和初始化:

为什么一定要销毁video.js呢?这个销毁不是指你vue页面的destroyed,即使你关闭了页面,websocket断掉,但是他这个videojs还会继续解析地址,并不会销毁,所以会出现大量的报错,2分钟不管,或者你切换到别的页面后,用一会,浏览器就崩溃了。然后就是当你销毁掉,再打开这个页面的时候,如何重新创建和重新初始化,你总不可能逼着用户,每次切换这个页面的时候让强制他重新刷浏览器吧?不会吧?不会吧?

难点4:选择不同摄像头(就是那个树形菜单,有的点了之后是一屏,有的点了之后是展开,有的点了之后是多屏),以及点击某个摄像头调整他的视角和直播的联动(点击摄像头调整位置这个简单)

难点5 :所有东西联动

这个比较难,因为他涉及到了初始化页面;数据重新渲染顺序;初始化直播;然后树形菜单的默认选中;然后请求到数据显示直播后,再点击分屏或者摄像头切换的时候videojs的销毁和video的创建和初始化等


方法二:使用websoclet连接后端返回一张一张的图片,然后不停换图片以达到视频的效果(话说视频的原理不就是一帧一帧的穿起来的吗?)

重难点分析

重点:没什么重点吧…他就是个拿值然后赋值的过程也用不到销毁video什么的

难点:当你多个websoclet拿到值后,要循环渲染到页面上

因为你img是循环出来的,并不是双向绑定,所以你会发现不管怎么绑,他都是只有一张图片,并不会切换图片,所以要用到 this.$set 来强行赋值


方法一

上代码,复制出来研究吧,在这看不明白,每个函数都有注释

	<!--树形菜单  具体属性翻element官网即可-->
    <el-tree 
        :current-node-key="defaultChecked" 
        :default-expanded-keys="defaultExpanded" 
        node-key="id" 
        :highlight-current="true" 
        ref="tree"  
        :data="treeData" 
        :props="defaultProps" 
        accordion 
        @node-click="handleNodeClick"
        :filter-node-method="filterNode"
    ></el-tree>
	

	<!--云台  这里到没什么,简单的请求接口-->
    <div v-if="ISholder" class="pa yuntai" :style="{height: rightScrollHeight}">
        <div @click="yuntaiOpen()" class="yuntai-title">{{siteName}}</div>
        <div>
            <div class="yuntai-ctl-box">
                <div class="yuntai-ctl-direction">
                    <div class="yuntai-ctl-direction-item">
                        <img @click="handlPtz(25)" src="~@/assets/img/RealVideo/zuoshang.png" alt="">
                        <img @click="handlPtz(21)" src="~@/assets/img/RealVideo/shang.png" alt="">
                        <img @click="handlPtz(26)" src="~@/assets/img/RealVideo/youshang.png" alt="">
                        <img @click="handlPtz(23)" src="~@/assets/img/RealVideo/zuo.png" alt="">
                        <img src="~@/assets/img/RealVideo/shuaxin.png" alt="">
                        <img @click="handlPtz(24)" src="~@/assets/img/RealVideo/you.png" alt="">
                        <img @click="handlPtz(27)" src="~@/assets/img/RealVideo/youxi.png" alt="">
                        <img @click="handlPtz(22)" src="~@/assets/img/RealVideo/xia.png" alt="">
                        <img @click="handlPtz(28)" src="~@/assets/img/RealVideo/youx.png" alt="">
                    </div>
                </div>
                <div class="yuntai-ctl-other">
                    <div>
                        <img width="40px" style="margin: 5px;cursor: pointer;" @click="handlPtz(13)" src="~@/assets/img/RealVideo/jia.png" alt="">
                        <span style="margin:0 10px;">缩放</span>
                        <img width="40px" style="margin: 5px;cursor: pointer;" @click="handlPtz(14)" src="~@/assets/img/RealVideo/jian.png" alt="">
                    </div>
                    <div>
                        <img width="40px" style="margin: 5px;cursor: pointer;" @click="handlPtz(11)" src="~@/assets/img/RealVideo/jia.png" alt="">
                        <span style="margin:0 10px;">聚焦</span>
                        <img width="40px" style="margin: 5px;cursor: pointer;" @click="handlPtz(12)" src="~@/assets/img/RealVideo/jian.png" alt="">
                    </div>
                    <div>
                        <img width="40px" style="margin: 5px;cursor: pointer;" @click="handlPtz(23)" src="~@/assets/img/RealVideo/xuanzhuan.png" alt="">
                        <span style="margin:0 10px;">旋转</span>
                        <img width="40px" style="margin: 5px;cursor: pointer;" @click="handlPtz(24)" src="~@/assets/img/RealVideo/xuanzhuan1.png" alt="">
                    </div>
                </div>
            </div>
            <div class="yuntai-speed">
                <div class="yuntai-speed-speed" ><span>云台速度</span> </div>
                <div class="yuntai-speed-silder" >
                    <el-slider :max="7" @change="handleYunKongZhi()" v-model="yuntaiSpeed"></el-slider>
                </div>
            </div>
            <div class=yuntai-repect>
                <el-button class="yuntai-button blue" type="">复位</el-button>
            </div>
        </div>
    </div>
<!--视频  这里重点说一下-->
   <div class="center h100per">
       <div class="center-top">
           <div class="flex-wrap">
               <div class="videoContainer" >
                   <el-row style="margin:0" class="video-box" :gutter="20">
                       <!--videoNum 这个就是代表了你页面有多少个视频在播放-->
                       <el-col class="borders" :class="currentIndex === index ?'active':''" v-for="(item,index) in videoNum" :key="item.id" :span="videoctl">
                           <!--height 高是动态的 --->
                           <div :style="{height:screenHeight}" :id='"myidFather"+index' class="temp-bg">
                               <div class="video-name"> {{item.name}} </div>
                               <!--	
                               		click 点击事件
                               		play 播放事件(点击事件和播放事件不一样,别混)
                               		style 他的高也是动态的
                               		poster 封面图
                               		id 要给id,要不然你初始化的时候没发初始化
                               --->
                               <video
                                   @click="getVideos(item,index)"
                                   @play="handleInitLive(index)"
                                   :style="{height:screenHeight}"
                                   style="width:100%"
                                   :poster="item.url"
                                   :id='"myid"+index'
                                   class="video-js vjs-default-skin vjs-big-play-centered"
                                   controls
                                   preload="auto">
                                   <!--这里就不用说了吧 --->
                                   <source :ref='"previewSource"+index' type="application/x-mpegURL" :src="item.previewUrl">
                               </video>
                           </div>
                       </el-col>
                   </el-row>
                   <div class="screen-ctl">
                       <div v-if="ISholder" style="float:left;margin-left:20px">
                           <div class="YUbutton blue" v-if="recording" @click="record" > <img src="~@/assets/img/RealVideo/luxiang.png" alt=""> 录像 </div>
                           <div class="YUbutton blue" style="text-align:center" v-if="!recording" @click="recordStop" >  停止录像 </div>
                           <div class="YUbutton blue"  @click="printscreen"> <img style="width:20px;" src="~@/assets/img/RealVideo/jietu.png" alt=""> 截图 </div>
                       </div>
                       <div v-else style="float:left;margin-left:20px">
                           <div class="YUbutton"> <img src="~@/assets/img/RealVideo/luxiang.png" alt=""> 录像 </div>
                           <div class="YUbutton"> <img style="width:20px;" src="~@/assets/img/RealVideo/jietu.png" alt=""> 截图 </div>
                       </div>
                       <div v-if="ISscreen" class="screenBtn" style="">
                           <div @click="handlChangeScreen(1)"></div><!--1屏-->
                           <i @click="handlChangeScreen(4)" class="el-icon-menu"></i><!--4屏-->
                           <i @click="handlChangeScreen(9)" class="el-icon-s-grid"></i><!--9屏-->
                       </div>
                   </div>
               </div>
           </div>
       </div>
   </div>


    import 'videojs-contrib-hls'
    import Cookies from 'js-cookie' 
    
    data(){
        return {
            player:'',//播放器
            myPlayer:'',//选中的分屏
            selectId:'',//云台速度
            yuntaiSpeed:0,//树形菜单默认选中
            defaultChecked:'',//默认展开
            defaultExpanded:[],//分配控制
            screenCtl:4,//分屏默认展示4个
            videoNum:[ //默认给4个空的
                {
                    id:1,
                },
                {
                    id:2,
                },
                {
                    id:3,
                },
                {
                    id:4,
                }
            ],
            videoctl:12,//el-col 的占比
            screenHeight: '359px',//动态高度高
            noneHeight:'23%',// 动态高度
            filterText:'',//树形菜单过滤
            treeData:[],// isImgVideo:true,
            defaultProps: {//树形菜单选项转化
                children: 'children',
                label: 'name'
            },
            rightScrollHeight: '55px',//云台高度
            player: undefined,//播放器 我这里设置的是undefined,因为在下面我要判断他是否创建过了,不要问我为什么不用空串 ‘’ 因为不行
            isyuntai:false, //云台
            websocket: [],//websocket数组
            siteIdScreen:'',//传给后端的分屏量
            cameraArr:[],//保存的摄像头数组
            siteIdIndex:'', //保存的直播下标
            currentIndex:'',//视频选中索引
            ISholder:false,//是否展示云台控件和录像截图控件
            ISscreen:true,//是否展示分屏控件
            recording:true,//是否开始录像
            siteName:'',//摄像机名称
            siteId:'',//摄像机id
            websocketPush:''//websocket一个的时候
        }
    },
	
	//这个就不用说了吧,element自带的,抄一下就行
   watch:{
       //树形菜单搜索
       defaultChecked(id){
           // Tree 内部使用了 Node 类型的对象来包装用户传入的数据,用来保存目前节点的状态。可以用 $refs 获取 Tree 实例
           this.$nextTick(() => {
               if (id) {
                   this.$refs["tree"].setCurrentKey(id);
               } else {
                   this.$refs["tree"].setCurrentKey(null);
               }
           })
       },
       //树形菜单搜索
       filterText(val) {
           this.$refs.tree.filter(val);
       }
   },

    mounted(){
        //加载树形菜单列表
        this.fetchRealTimeData();
    },
    created:function(){
        this.$nextTick(() => {
            //初始化直播video
            this.handleInitLive()
        })
    },

	methods:{
	
        //树形菜单搜索
        filterNode(value, data) {
            if (!value) return true;
            return data.name.indexOf(value) !== -1;
        },
        //树形菜单列表
        fetchRealTimeData(){
        		// 这里请求接口拿到数据
                this.treeData = res.data;
                
                if (this.treeData[0]) {
                    if (this.treeData[0].children.length !==0) {
						//赋值一大堆默认值
                        this.defaultExpanded = [this.treeData[0].id]
                        this.selectId = this.treeData[0].children[0].id
                        this.defaultChecked = this.treeData[0].children[0].id 
                        
                        this.handleInitLive()//先初始化直播
                        
                        var temp = this.treeData[0].children[0].children
                        for (let i = 0; i < temp.length; i++) {
                            this.cameraArr.push(temp[i].id)
                        }
                        this.getSiteListLevleTwo(4)
                    }
                }
                
        },
        //树形菜单点击事件
        //level 是element自带的
        handleNodeClick(data, node) {
            if(node.level !== 1){	//一级
                this.selectId = data.id
            }
            if(node.level == 2){	//二级,
                this.ISholder = false
                this.ISscreen = true
                this.cameraArr = []
                for (let i = 0; i < data.children.length; i++) {
                    this.cameraArr.push(data.children[i].id)
                }
                this.getSiteListLevleTwo(4)//因为这里默认是多个视频,所以默认分4屏
                this.handlChangeScreenTree(4)
            }
            if(node.level == 3){	//三级
                for (let i = 0; i < this.websocket.length; i++) {
                    this.websocket[i].close()
                }
                //如果有视频播放,先干掉,然后再初始化
                if (typeof (this.player) != "undefined") {
                    this.player.dispose()  //销毁
                    this.player = undefined
                    this.videoNum = []
                }
                this.websocket = []
                this.videoNum = []
                this.ISholder = true
                this.ISscreen = false
                
                this.siteId = data.id
                this.siteName = data.name
                //然后走这个函数,把data传过去
                this.getSiteListLevleFore(data.id)
            }
        },

        //树形菜单点击第三级
        getSiteListLevleFore(index){
            this.$message('远程数据加载中,请稍后')
            this.handlChangeScreenTree(index)
            //请求数据
            this.$http.get('/video/hikdevice/capturePics?ids='+index+'&limit=1').then(({ data: res }) => {
                if (res.code !== 0) {
                    return this.$message.error(res.msg)
                }
                this.videoNum = res.data
                this.videoNum[0].previewUrl = ''
                this.siteIdIndex = 0
                this.$nextTick(() => {
                    this.createWebSocket();//连websocket
                })
                this.handlChangeScreenTree(1)//,因为三级菜单这里只有一个视频,所以只分一屏即可
                
            }).catch(() => {})
        },
		
		
        //树形菜单点击,以及补全分屏函数
        getSiteListLevleTwo(index){
            this.$message('远程数据加载中,请稍后')
            this.handlChangeScreenTree(index)
            this.$http.get('/video/hikdevice/capturePics?ids='+ this.cameraArr.join()+'&limit='+index ).then(({ data: res }) => {
                if (res.code !== 0) {
                    return this.$message.error(res.msg)
                }
                if (res.code !== 0) {
                    var arr = []
                    var temp = 1
                    for (let i = 0; i < index; i++) {
                        let obj = {
                            id: temp ++
                        }
                        arr.push(obj)
                    }
                    this.videoNum = arr
                    return this.$message.error(res.msg)
                }else{
                    this.videoNum = res.data;
                    //补全videoNum 
                    if (this.videoNum.length !==0) {
                        if (index == 1) {
                            this.videoNum = res.data;
                        }
                        if (index == 4) {
                            for (let i = 0; i <= 4; i++) {
                                if (this.videoNum.length<4) {
                                    var obj = {
                                        id:i++
                                    }
                                    this.videoNum.push(obj)
                                }
                            }
                        }
                        if (index == 9) {
                            for (let i = 0; i <= 9; i++) {
                                let temp = 0
                                if (this.videoNum.length<9) {
                                    var obj = {
                                        id:temp++
                                    }
                                    this.videoNum.push(obj)
                                }
                            }
                        }
                    }
                    else{
                        var arr = []
                        var temp = 1
                        for (let i = 0; i < index; i++) {
                            let obj = {
                                id: temp ++
                            }
                            arr.push(obj)
                        }
                        this.videoNum = arr
                    }
                    for (let i = 0; i < this.videoNum.length; i++) {
                        this.videoNum[i].previewUrl = ''
                    }
                }
                
            }).catch(() => {})
        },

       //视频播放
       getVideos(item,index){
           console.log(this.recording);
           //多个播放版本
           if (this.ISholder) {
                   
               if (!this.recording) {
                   this.$message.warning('请停止录像后操作')
                   return false
               }
           }
           if (item.name) {
               var arr = []
               for (let i = 0; i < this.websocket.length; i++) {
                   arr.push(this.websocket[i].siteId)
               }
               if (arr.indexOf(item.id)>-1) {
                   this.currentIndex = index
                   this.siteId = item.id
                   this.siteName = item.name
                   this.siteIdIndex = index
               }else{
                   this.currentIndex = index
                   this.siteId = item.id
                   this.siteName = item.name
                   this.siteIdIndex = index
                   this.createWebSocket();
               }
           }else{
               this.ISholder = false
               this.currentIndex = index
           }
       },

       //工具函数,找元素
       filePush1(item){
           let that=this
           let refs=that.$refs
           for(let key in refs){
               return refs[item]
               //这里遍历循环所有的 refs值 就可以拿到动态拼接$refs所要的对应值 这的item  是动态传的值  
           }
       },

       //开始创建WebSocket
       createWebSocket(){
           try {
               //尝试连接
               this.websocketPush = new WebSocket(`${window.SITE_CONFIG['VideoPreviewSocketURL']}?token=${Cookies.get('token')}`)
               this.initWebSocket();
           } catch (e) {
               console.log(e);
           }
       },

       // 初始化weosocket
       initWebSocket() {
           this.websocketPush.onopen = this.websocketonopen;      
           this.websocketPush.onerror = this.websocketonerror;     
           this.websocketPush.onmessage = this.websocketonmessage; 
           this.websocketPush.onclose = this.websocketclose;
       },
       //连接成功提示字样
       websocketonopen() {
           console.log('连接成功');
           this.websocketPush.siteId = this.siteId
           this.websocket.push(this.websocketPush)
           this.websocketsend(this.siteId)
       },

        //连接错误
        websocketonerror(e) {
            console.log(e);
        },
        //数据接收
        websocketonmessage(e) {
            if (res.code == '0') {
                this.$message.success(res.data)
            }
            if(res.code == 1){
                this.downLoad(res.data)
            }
            if (res.code == 3) {
                this.ISholder = true
                this.$message.success('直播初始化完毕')
                this.videoNum[this.siteIdIndex].previewUrl=res.data
                this.$nextTick(() => {
                    this.filePush1('previewSource'+this.siteIdIndex)[0].src = res.data
                    this.handleInitLive(this.siteIdIndex)

                })
            }
            if (res.code == 500) {
                this.$message.warning('服务器正忙,请重试')
            }
        },
        
       //数据发送
       websocketsend(item){
           for (let i = 0; i < this.websocket.length; i++) {
               if (this.websocket[i].siteId == item) {
                   var obj={id:item,record:3}
                   this.websocket[i].send(JSON.stringify(obj))
               }else{
               }
           }
       },

        //服务关闭
        websocketclose(e) {
            console.log("connection closed ");
        },
        //真正的关闭
        websocketcloses(){
            this.websocket.close()
        },
        //点击分屏请求接口
        hanldfetchDevicePage(index){
            for (let i = 0; i < this.websocket.length; i++) {
                this.websocket[i].close()
            }
            this.websocket = []
            this.siteIdScreen = index
            this.getSiteListLevleTwo(index)

        },
        
        //分屏点击事件
        handlChangeScreen(item){
            switch (item) {
                case 1:
                    this.screenCtl = 1
                    this.videoctl = 24
                    this.screenHeight = '720px'
                    this.noneHeight = '24%'
                    this.hanldfetchDevicePage(this.screenCtl)
                    break;
                case 4:
                    this.screenCtl = 4
                    this.videoctl = 12
                    this.screenHeight = '359px'
                    this.noneHeight = '23%'
                    this.hanldfetchDevicePage(this.screenCtl)
                    break;
                case 9:
                    this.screenCtl = 9
                    this.videoctl = 8
                    this.screenHeight = '238px'
                    this.noneHeight = '20%'
                    this.hanldfetchDevicePage(this.screenCtl)
                    break;
            
                default:
                    this.screenCtl = 4
                    this.videoctl = 12
                    this.screenHeight = '359px'
                    this.noneHeight = '23%'
                    this.hanldfetchDevicePage(this.screenCtl)
            }
        },

       //分屏事件(不请求接口)
       handlChangeScreenTree(item){
           switch (item) {
               case 1:
                   this.screenCtl = 1
                   this.videoctl = 24
                   this.screenHeight = '720px'
                   this.noneHeight = '24%'
                   // this.selectId
                   break;
               case 4:
                   this.screenCtl = 4
                   this.videoctl = 12
                   this.screenHeight = '359px'
                   this.noneHeight = '23%'
                   break;
               case 9:
                   this.screenCtl = 9
                   this.videoctl = 8
                   this.screenHeight = '238px'
                   this.noneHeight = '20%'
                   break;
           
               default:
                   this.screenCtl = 4
                   this.videoctl = 12
                   this.screenHeight = '359px'
                   this.noneHeight = '23%'
           }
           
       },
       //初始化直播列表
       handleInitLive(index){
           for (let i = 0; i < this.videoNum.length; i++) {
               if (this.videoNum[i].name) {
                   this.$nextTick(() => {
                       setTimeout(() => {
                           this.player = this.$video(document.getElementById('myid'+index+''), {
                               controls: true,
                               autoplay: false,
                               preload: 'auto',
                               controlBar:{
                                   playToggle:true
                               }
                           })
                       }, 500);
                   })
               }
           }
       },
       //页面销毁
       destroyed: () =>{
           this.player.dispose();  //销毁
           this.$video.dispose();
       },
       //云台方向控制
       handlPtz(cmd){
           var obj = {
               id:this.siteId,
               command:cmd
           }
           this.$http.post('/video/hikdevice/ptzControl', obj).then(({ data: res }) => {
           if (res.code !== 0) {
               return this.$message.error(res.msg)
           }
           
           }).catch(() => {})
       },
       //调节云台速度
       handleLiveWebSocket(){
           var obj = {
               id:this.siteId,
               speed:this.yuntaiSpeed
           }
           this.$http.post('/video/hikdevice/ptzControl', obj).then(({ data: res }) => {
           if (res.code !== 0) {
               return this.$message.error(res.msg)
           }
           
           }).catch(() => {})
       },
		//停止录像
       recordStop(){
           this.recording = true
           let actions = {id:this.siteId,record:0};
           for (let i = 0; i < this.websocket.length; i++) {
               if (this.websocket[i].siteId == this.siteId) {
                   this.websocket[i].send(JSON.stringify(actions));
               }
           }
       },
       //截屏
       printscreen(){
           this.$http.get('video/hikdevice/capturePic?id='+this.siteId+'&name='+this.siteName).then(({ data: res }) => {
               var obj={
                   id:this.siteId,
                   name:this.siteName
               }
               var params = qs.stringify({
                   'token': Cookies.get('token'),
                   ...obj
               })
               window.location.href = `${window.SITE_CONFIG['apiURL']}/video/hikdevice/capturePic?${params}`

           }).catch(() => {})
       },
	}

方法二

大致和上面一样,就是接收数据和页面展示方式不太一样,然后你需要创建两个部分websocket,一部分是只有一张图片的时候,另一部分是多个websocket的时候,然后把销毁函数什么的删了就行了


    <el-tree    
        :current-node-key="defaultChecked"
        ref="tree"
        class="filter-tree"
        default-expand-all 
        node-key="id" 
        :filter-node-method="filterNode" 
        :data="data" 
        :props="defaultProps" 
        @node-click="handleNodeClick"
    ></el-tree>

    <div class="flex-wrap">
        <div class="videoContainer" v-if="!isOne">
            <!-- 多个 -->
            <div class="videoContainer-box" style="overflow:auto;">
                <div class="videoContainer-item" style="float:left" v-for="(item,index) in videoData" v-bind:key="item.id">
                    <div 
                        v-loading="loading[index]" 
                        element-loading-text="视频加载中"
                        element-loading-spinner="el-icon-loading"
                        element-loading-background="rgba(0, 0, 0, 0.8)"
                        style="width:600px;height:360px;margin:20px;">
                            <img style="width:100%"  :src="videoData[index].src" alt="">
                        </div>
                </div>
            </div>
            <div style="text-align:center">
                <el-pagination
                    @size-change="handleSizeChange"
                    @current-change="handleCurrentChange"
                    :current-page="pageNum"
                    :page-size="pageSize"
                    layout="total, prev, pager, next"
                    :total="total">
                </el-pagination>
            </div>
        </div>
        <div class="videoContainer-one" v-if="isOne">
            <!-- 一个 -->
            <div class="videoContainer-box" style="overflow:auto;">
                
                <!-- <div v-else> 加载中 </div> -->
                <div 
                    v-loading="loadingOne" 
                    element-loading-text="视频加载中"
                    element-loading-spinner="el-icon-loading"
                    element-loading-background="rgba(0, 0, 0, 0.8)"
                    style="width:97%;height:825px;margin:20px;">
                        <img style="width:100%;" :src="ImgSrc" alt="">
                    </div>
            </div>
        </div>
    </div>
   data(){
       return {
           loadingOne:true,
           loading:[
               true,
               true,
               true,
               true,
           ],
           ImgSrc:'',
           websocket: null,
           websocketArr:[],   //wensocket数组合集地址
           isOne:false,    //判断多个视频还是一个视频
           data: [],           
           pageNum:1,//当前页
           total:0,//总条数
           pageSize:4,
           //树形菜单默认选中
           defaultChecked:'',
           middleData:[],  //中间件
           oneSrc:'',      //一个视频播放的时候的地址
           videoData:[],
           //默认展开
           defaultExpanded:[],
           //树形菜单过滤
           filterText:'',
           //树形菜单选项转化
           defaultProps: {
               children: 'children',
               label: 'name'
           },
           tempVideoArr:[]
       }
   },
   mounted() {
       
       // this.createWebSocket(0)
       videoTree().then(response => {
       //老规矩,还是从树形菜单下手
           console.log(response);
           this.data = response.data
           this.defaultChecked = this.data[0].id
           this.middleData = this.data[0].children || 0
           var lengths = this.middleData.length
           this.total = lengths

         this.demoData();

       });
   },
	methods:{
        demoData(){
            if (this.middleData.length>4) {
                this.videoData = this.returnArea(this.middleData,0)
                this.FORE_VIDEO_WEBSOCKET()
            }
        },
        //一个视频的时候
        ONE_VIDEO_WEBSOCKET(data){
            this.createWebSocketOne(data)
        },
        //多个视频的时候
        FORE_VIDEO_WEBSOCKET(){

            for (let i = 0; i < this.videoData.length; i++) {
                if (this.videoData[i].id) {
                    this.createWebSocket(i,this.videoData[i])
                }else{

                }
            }
        },
        //一个视频关闭连接
        ONE_CLOSE_WEBSOCKET(){
            this.websocket.close()
            this.websocket = null
        },
        //多个视频关闭连接
        FORE_CLOSE_WEBSOCKET(isgo){
            console.log(this.websocketArr);
            for (let i = 0; i <= this.websocketArr.length; i++) {
                if (this.websocketArr[i]) {
                    console.log('断');
                    this.websocketArr[i].close();
                }
            }
            console.log(this.websocketArr);
            this.websocketArr = []
            this.videoData = []
            if (isgo) {
                this.pageNum = this.pageNum
                this.returnArea(this.middleData,this.pageNum)
            }
        },
        handleSizeChange(val) {
            console.log(`每页 ${val}`);
        },
        handleCurrentChange(val) {
            console.log(val);
            this.pageNum = val

            this.FORE_CLOSE_WEBSOCKET(true)
            // console.log(`当前页: ${val}`);
        },
        //树形菜单搜索
        filterNode(value, data) {
            if (!value) return true;
            return data.name.indexOf(value) !== -1;
        },
        
        //0-4   1
        //4-8   2
        //8-12  3
        returnArea(tempVideoArr,one){
            console.log(tempVideoArr);
            console.log(one);
            if (one == 0) {
                return tempVideoArr.slice(0,4)
            }else{
                console.log(999);
                // console.log((one-1)*4);
                // console.log(one*4);
                // console.log(tempVideoArr.slice( ((one-1)*4), one*4));
                // return tempVideoArr.slice( ((one-1)*4), one*4)
                this.polishing(tempVideoArr.slice(((one-1)*4), one*4))
            }
        },
        polishing(data){
            console.log(data);
                console.log(777);
            for (let i = 0; i < data.length; i++) {
                if (data.length <4) {
                    data.push({})
                }
            }
            this.videoData = data
            this.FORE_VIDEO_WEBSOCKET()
        },
        handleNodeClick(data,v) {
            if (v.level == 1) {
                if (this.videoData.length>0) {
                    this.FORE_CLOSE_WEBSOCKET()
                    this.ONE_CLOSE_WEBSOCKET()
                    this.ImgSrc = ''
                    this.videoData = []
                    this.isOne = false
                    console.log(data);
                    this.middleData = data.children
                    if (this.middleData.length>4) {
                        //开启连接
                        console.log(this.returnArea(this.middleData,0));
                        this.videoData = this.returnArea(this.middleData,0)
                        console.log(this.videoData);
                        this.FORE_VIDEO_WEBSOCKET()
                    }else{
                        console.log(777);
                    }
                }else{
                    this.ImgSrc = ''
                    this.videoData = []
                    this.isOne = false
                    console.log(data);
                    this.middleData = data.children
                    if (this.middleData.length>4) {
                        //开启连接
                        console.log(this.returnArea(this.middleData,0));
                        this.videoData = this.returnArea(this.middleData,0)
                        console.log(this.videoData);
                        this.FORE_VIDEO_WEBSOCKET()
                    }else{
                        console.log(777);
                    }
                }

            }else{ 

                // this.ONE_VIDEO_WEBSOCKET(data)
                console.log(this.websocket);
                if (this.websocket) {
                    //多个关闭
                    this.ONE_CLOSE_WEBSOCKET()
                    this.videoData = []
                    this.isOne = true
                    this.ImgSrc = ''
                    this.ONE_VIDEO_WEBSOCKET(data)
                }else{
                    //多个关闭
                    this.FORE_CLOSE_WEBSOCKET()
                    this.ONE_VIDEO_WEBSOCKET(data)
                    this.videoData = []

                    this.pageNum = 1
                    this.isOne = true
                }

            }
        },


        
        //第一部分WebSocket
        createWebSocketOne(data){
            this.$message('远程数据连接中,请稍后')
            try {
                //尝试连接
                this.websocket = new WebSocket('ws://172.16.99.2:8091/company/supervision/websocket/video/preview?Authorization='+this.$store.state.user.token)
                this.initWebSocketOne(data);
            } catch (e) {
                console.log(e);
            }
        },
        // 初始化weosocket
        initWebSocketOne(data) {
            var that = this
            this.websocket.onopen = function(){
                // console.log();
                // console.log(data);
                console.log('连接成功');
                //数据发送
                that.websocketsendOne(data)
            }
            this.websocket.onerror = this.websocketonerrorOne;
            this.websocket.onmessage = function(e){
                
                // console.log(e.data);
                // console.log(JSON.parse(e.data));
                var json = JSON.parse(e.data)

                if (json.code ==500) {
                    that.loadingOne = true
                    that.ImgSrc = ""
                }else{
                    that.loadingOne = false
                    that.ImgSrc = "data:" +';base64,'+json.data
                }
                
            };
            this.websocket.onclose = this.websocketcloseOne;
        },
        //连接错误
        websocketonerrorOne(e) {
            console.log(e);
        },
        //数据发送
        websocketsendOne(data){
            var tempObj = {
                id: data.id,
            }
            console.log(tempObj);
            this.websocket.send(JSON.stringify(tempObj));
        },
        //服务关闭
        websocketcloseOne(e) {
            console.log("connection closed ");
        },
        //真正的关闭
        websocketclosesOne(){
            this.websocket.close()
        },




        //第二部分WebSocket
        createWebSocket(wsobj,data){
            this.$message('远程数据连接中,请稍后')
            try {
                //尝试连接
                this.websocketArr[wsobj] = new WebSocket('ws://172.16.99.2:8091/company/supervision/websocket/video/preview?Authorization='+this.$store.state.user.token)
                this.initWebSocket(wsobj,data);
            } catch (e) {
                console.log(e);
            }
        },
        // 初始化weosocket
        initWebSocket(wsobj,data) {
            var that = this
            this.websocketArr[wsobj].onopen = function(){
                // console.log(wsobj);
                // console.log(data);
                console.log('连接成功');
                //数据发送
                that.websocketsend(wsobj,data)
            }
            this.websocketArr[wsobj].onerror = this.websocketonerror;
            this.websocketArr[wsobj].onmessage = function(e){

                // console.log(e.data);
                // console.log(JSON.parse(e.data));
                var json = JSON.parse(e.data)
                // console.log(json);
                if (json.code ==500) {
                    that.loading[wsobj] = true
                    var tempObj = {
                        ...that.videoData[wsobj],
                        src: ""
                    }
                    that.$set(that.videoData,wsobj,tempObj);
                }else{
                    that.loading[wsobj] = false
                    var tempObj = {
                        ...that.videoData[wsobj],
                        src: "data:" +';base64,'+json.data
                    }
                    that.$set(that.videoData,wsobj,tempObj);
                    // that.oneImg = "data:" +';base64,'+e.data
                }
            };
            this.websocketArr[wsobj].onclose = this.websocketclose;
            console.log(this.websocketArr);
        },
        //连接成功提示字样
        websocketonopen(wsobj,data) {
        },
        //连接错误
        websocketonerror(e) {
            console.log(e);
        },
        //数据发送
        websocketsend(wsobj,data){
            // console.log(wsobj);
            // console.log(data);
            var tempObj = {
                id: data.id,
            }
            console.log(tempObj);
            this.websocketArr[wsobj].send(JSON.stringify(tempObj));
            // console.log(this.websocketArr);
        },
        //服务关闭
        websocketclose(e) {
            console.log("connection closed ");
        },
        //真正的关闭
        websocketcloses(){
            this.websocketArr[wsobj].close()
        },
    },

    destroyed(){
        
        this.FORE_CLOSE_WEBSOCKET()
        this.ONE_CLOSE_WEBSOCKET()
        this.videoData = []
        this.ImgSrc = ''
    },

OK,大致就是这样了,因为我这个是两个demo,视频的一个,图片的一个

总结

其实写完就会发现,没什么难的,把逻辑梳理清楚,其他的就是时间问题,喜欢的话点赞收藏转发支持一下~

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-10-11 17:52:51  更:2021-10-11 17:55:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:38:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码