功能:ant Design vue使用腾讯播放器实现监控视频直播、点播,多个视频同时播放

效果图:在这里插入图片描述
自适应布局
在这里插入图片描述

第一步安装npm包

npm install tcplayer@0.0.24 --save

第二步封装子组件

<template >
  <div :id="`video_container_${index}`" class="video_container"></div>
</template>
<script>
import { TcPlayer } from 'tcplayer'
export default {
  name: 'Cviewplayer',
  props: {
    //默认监控图片
    Defaultimage: { type: String, default: '' },
    //视频的url
    videoUrl: { type: String, default: '' },
    //视频的坐标,用于判断div的id赋值到对应的容器
    index: { type: Number, default: 0 },
    //是否播放
    isPlay: { type: Boolean, default: false },
  },
  data() {
    return {
      player: [],
      poster: '' /* 视频封面 */,
    }
  },
  created() {
    this.$nextTick(() => {
      this.initPlayer()
    })
  },
  watch: {
    isPlay() {
      this.$nextTick(() => {
        if (this.isPlay) {
          this.play()
          this.$emit('PlayClose', false)
        }
      })
    },
  },
  methods: {
    initPlayer() {
      if (this.player.length) {
        this.player.forEach((item) => {
          item.destroy()
        })
        this.player = []
      }
      var options = {
      	//视频地址
        m3u8: this.videoUrl,
        flv: this.videoUrl,
        //是否自动播放
        autoplay: false,
        preload: true,
        //暂停时视频封面
        poster: { style: 'cover', src: this.Defaultimage },
        coverpic: this.Defaultimage,
        // live: live,
        width: '100%',
        height: '100%',
        x5_player: true,
        x5_type: 'h5-page',
        x5_fullscreen: true,
        wording: {
          1: '网络错误,请检查网络配置或者播放连接是否正确',
          1002: '即将开始,请稍等',
          2032: '请求视频失败,请检查网络',
          2048: '请求m3u8文件失败,多是网络错误或者跨域问题',
        },
        flash: false, //是否优先使用 flash 播放视频
        pausePosterEnabled: true /* 暂停时显示封面 默认为true */,
        listener: (msg) => {
          if (msg.type == 'load') {
            //加载完事件
            // this.player.play()
          }
          if (msg.type == 'ended') {
            //播放完成事件
            // this.player[this.index].close()
          }
          // 播放失败,重新连接
          if (msg.type == 'error') {
            setTimeout(() => {
              if (this.player[this.index]?.options.src == undefined) return false
              this.player[this.index]?.load() // 重连
            }, 4000)
          }
        },
      }
      // 初始化
      this.player.push(new TcPlayer('video_container_' + this.index, options))
    },
    // 播放或暂停
    play() {
      if (this.player.length) {
        this.player.forEach((item) => {
          //如果没有地址则跳过
          if (item.options.src == undefined) return false
          item?.play()
        })
      } else {
        this.$message.warning('暂无视频播放源,请检查设置')
      }
    },
  },
}
</script>
<style lang="less" scoped>
.video_container {
  width: 100%;
  height: 100%;
}
// 修改视频提示语位置
/deep/ .vcp-error-tips {
  padding-top: 66px;
}
</style>


第三步父组件调用

<template>
  <div class="b-wrapper">
    <!-- 按钮组 -->
    <div class="buttonList">
      <a-button type="primary" @click="VideoPlay">播放</a-button>
      <a-button @click="proportionSumbit(1)">1:1</a-button>
      <a-button @click="proportionSumbit(2)">2:2</a-button>
      <a-button @click="proportionSumbit(3)">3:3</a-button>
      <a-button @click="proportionSumbit(4)">4:4</a-button>
    </div>
    <!-- 视频组 -->
    <div class="VideoGirus" :style="`grid-template-columns:${autoNumber} `">
      <div v-for="(item, index) in Proportion" :key="index">
        <div class="colvideo">
          <div
            class="titlevideo"
            :style="`color:${com.config.textColor};font-weight: ${
              com.config.textWeight == true ? '600' : 'normal'
            };font-size: ${com.config.textSize};`"
            v-show="com.config.isShow"
          >
            {{ item.title }}
          </div>
          <cviewplayer
            class="cviewplayer"
            :key="freshDom"
            :videoUrl="item.videoUrl"
            :index="item.index"
            :isPlay="isPlay"
            @PlayClose="PlayClose"
          ></cviewplayer>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
//这个是引用子组件
import cviewplayer from './cview-player'
export default {
  name: 'BVideoMonitor',
  components: { cviewplayer },
  data() {
    return {
      //赋值时间戳达到刷新的效果
      freshDom: '',
      //数据的数组
      Proportion: [],
      //判断比例
      autoNumber: 'auto auto auto auto',
      //是否播放
      isPlay: false,
      //存储数据的变量
      com:{
			//配置
			config:{
			//标题颜色
			textColor:'',
			//字体大小
			textSize:'',
		    //默认展示比例: 1(1:1)  2(2:2)  3(3:3)  4(4:4)
   			 defaultProportion: 2,
			//是否显示标题栏
			isShow:true,
			 //字体大小
		    textSize: 'small', //medium / small / mini
		    //字体加粗
		    textWeight: false,
		    //用于播放首个视频用
		    showVideo: {},
		    //是否数据新增,修改,删除
		    isDataUpdate: false
		  },
		  //数据
		  apiData:{
			data:[
					{
						//视频唯一id
						id:'0',
						//视频状态 根据业务自定义是否需要此字段
						status:0,
						//视频标题名称
						title:'视频地址标题名称',
						//视频地址
						videoUrl:'https://new.qqaku.com/20220508/s44ly5RX/1100kb/hls/index.m3u8'
					}
			]
		  }
	   },
    }
  },
  created() {
    this.fun_into()
  },
  watch: {
  //监听是否更改了视频数据源
    'com.config.isDataUpdate': {
      handler: function () {
        if (this.com.config.isDataUpdate) {
          this.proportionSumbit(this.com.config.defaultProportion)
          this.com.config.isDataUpdate = false
        }
      },
    },
  },
  methods: {
    //接收子级传来的是否播放状态
    PlayClose() {
      this.isPlay = false
    },
    //初始化
    fun_into() {
      this.proportionSumbit(this.com.config.defaultProportion)
    },
    //播放事件
    VideoPlay() {
      this.isPlay = true
    },
    //视频比例
    proportionSumbit(val) {
      //grid赋值比例的
      this.proportion(val)
      this.Proportion = []
      this.freshDom = +new Date()
      for (var i = 0; i < val * val; i++) {
        this.Proportion.push({
          id: this.com.apiData.data[i]?.id,
          status: this.com.apiData.data[i]?.status,
          title: this.com.apiData.data[i]?.title,
          videoUrl: this.com.apiData.data[i]?.videoUrl,
          index: i,
        })
      }
    },
    //grid赋值比例的
    proportion(val) {
      switch (val) {
        case 1:
          this.autoNumber = 'auto'
          break
        case 2:
          this.autoNumber = 'auto auto'
          break
        case 3:
          this.autoNumber = 'auto auto auto'
          break
        case 4:
          this.autoNumber = 'auto auto auto auto'
          break
        default:
          this.autoNumber = 'auto auto auto auto'
          break
      }
    },
  },
}
</script>
<style lang="less" scoped>
.b-wrapper {
  height: 100%;
  width: 100%;
  > .buttonList {
    width: 100%;
    margin-top: -10px;
    padding-bottom: 10px;
    display: flex;
    justify-content: flex-start;
    flex-direction: row;
    > button:first-child {
      margin: 0;
      width: 80px;
      height: 35px;
    }
    > button {
      margin-left: 10px;
      width: 80px;
      height: 35px;
    }
  }
  > .VideoGirus {
    width: 100%;
    height: 97%;
    // border: 1px dashed #000;
    display: grid;
    grid-column-gap: 5px;
    > div {
      width: 100%;
      height: 100%;
      display: inline-table;
      > .colvideo {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
        position: relative;
        > .titlevideo {
          // position: initial;
          overflow: hidden;
          white-space: nowrap;
          text-overflow: ellipsis;
          position: absolute;
          z-index: 1;
          height: 35px;
          width: 100%;
          background-color: #000;
          opacity: 0.7;
          font-size: 16px;
          padding: 4px 0 0 15px;
        }
        > .cviewplayer {
          position: absolute;
          width: 100%;
          height: 98%;
        }
      }
    }
  }
}
</style>

踩坑点

1.该功能中需要同时播放多个视频,因此需要给div赋值唯一的id :id=“video_container_${index}
2.因为是自适应布局所有需要给父组件最外层div赋值固定的高宽度
3.刷新视频数据源同时需要给子组件加key进行强制刷新 :key=“freshDom” this.freshDom = +new Date()
4.官网地址:播放器API文档
5.如果无法播放flv的视频,则可能是无法请求到http://cloudcache.tencent-cloud.com/open/qcloud/video/vcplayer/libs/flv.min.1.5.js文件的接口,这种一般是测试电脑局域网防火墙的问题

Logo

前往低代码交流专区

更多推荐