Aliplayer劫持全屏播放

比如有四路视频,使用el.requestFullscreen()想让它们全屏占满屏幕,但是Aliplayer会劫持全屏事件,导致只有一路视频是全屏的状态。想要的操作如下,如何不被劫持

阅读 2.3k
1 个回答

我自己封装了一个基于vue视频播放的组件需要的话可以回复
(功能包含1 4 6 9 16分屏切换)
组件目录
image.png
index.vue

<!--
视频宫格面板功能
-->
<template>
  <div class="cell">
    <div class="cell-tool">
      <div class="el-button-group">
        <el-button @click="cellCount = 1" size="small">1</el-button>
        <el-button @click="cellCount = 4" size="small">4</el-button>
        <el-button @click="cellCount = 6" size="small">6</el-button>
        <el-button @click="cellCount = 9" size="small">9</el-button>
        <!--        <el-button @click="cellCount = 16" size="small">16</el-button>-->
      </div>
    </div>
    <div class="cell-player">
      <div :class="cellClass(item.index)" v-for="(item, i) in cellVideoList" :key="i">
        <cell-player :title="item.videoTitle"
                     video-tag="video"
                     :video-url="item.videoUrl"
                     :ptz-params="item.ptzParams"
                     :class="{'cell-player-select': selectIndex === i}"
                     v-if="cellCount !== 6"
                     @change-clarity="changeClarity"
                     @click.native="cellPlayerClick(item.id, i)"></cell-player>

        <cell-player :title="item.videoTitle"
                     video-tag="video"
                     :video-url="item.videoUrl"
                     :ptz-params="item.ptzParams"
                     :class="{'cell-player-select': selectIndex === i}"
                     v-if="cellCount === 6 && item.index !== 2 && item.index !== 3"
                     @change-clarity="changeClarity"
                     @click.native="cellPlayerClick(item.id, i)"></cell-player>

        <template v-if="cellCount === 6 && item.index === 2">
          <div class="cell-player-6-2-cell">
            <cell-player :title="item.videoTitle"
                         video-tag="video"
                         :video-url="item.videoUrl"
                         :ptz-params="item.ptzParams"
                         :class="{'cell-player-select': selectIndex === i}"
                         @change-clarity="changeClarity"
                         @click.native="cellPlayerClick(item.id, i)"></cell-player>

            <cell-player :title="cellVideoList[i + 1].videoTitle"
                         video-tag="video"
                         :class="{'cell-player-select': selectIndex === i + 1}"
                         :video-url="cellVideoList[i + 1].videoUrl"
                         :ptz-params="cellVideoList[i + 1].ptzParams"
                         @change-clarity="changeClarity"
                         @click.native="cellPlayerClick(cellVideoList[i + 1].id, i + 1)"></cell-player>
          </div>
        </template>
      </div>
    </div>
  </div>
</template>


<script>
import cellPlayer from './cellPlayer.vue'

export default {
  name: "video-panel",
  // import引入的组件需要注入到对象中才能使用
  components: {
    cellPlayer
  },
  // 传递参数
  props: {
    // 视频播放列表
    videoList: {
      type: Object,
      default: null
    },
    // 选中的视频
    change: {
      type: Boolean,
      default: false
    }
  },

  // 这里存放数据
  data() {
    return {
      cellCount: 4,
      selectIndex: 0,
      videoId: 'video',
      videoChange: false
    };
  },
  // 生命周期 - 创建完成(可以访问当前this实例)
  created() {

  },
  // 监听属性 类似于data概念
  computed: {
    cellClass() {
      return function (index) {
        switch (this.cellCount) {
          case 1:
            return ['cell-player-1']
          case 4:
            return ['cell-player-4']
          case 6:
            if (index == 1)
              return ['cell-player-6-1']
            if (index == 2)
              return ['cell-player-6-2']
            if (index == 3)
              return ['cell-player-6-none']
            return ['cell-player-6']
          case 9:
            return ['cell-player-9']
          case 16:
            return ['cell-player-16']
          default:
            break;
        }

      }
    },
    cellVideoList() {

      const videoList = Object.keys(this.videoList)
      this.videoChange = this.change
      const list = this.cellList.map((item, i) => {
        let obj = {}
        if (videoList.includes(item.id)) {
          obj = this.videoList[item.id]
          obj.id = this.videoId + i
        } else {
          obj = {
            id: this.videoId + i,
            videoUrl: null,
            videoTitle: null,
            ptzParams: {
              ptzControlOrNot: false,
              id: null,
              camPlatform: 0
            }
          }
        }
        obj.index = item.index

        return obj
      })
      return list

    },
    cellList() {
      const list = []
      for (let i = 0; i < this.cellCount; i++) {
        list.push({
          index: i + 1,
          id: this.videoId + i,
          videoUrl: null,
          videoTitle: null
        })


      }
      return list
    },

  },
  // 监控data中的数据变化
  watch: {},
  // 方法集合
  methods: {
    // 根据选择的视频获取视频地址
    cellPlayerClick(id, index) {
      this.selectIndex = index
      this.$emit('cell-player-click', id)
    },
    changeClarity(id, definition) {
      this.$emit('change-clarity', id, definition)
    }
  },
  // 生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {

  },
  // 生命周期 - 销毁之前
  beforeDestroy() {
  },
  // 如果页面有keep-alive缓存功能,这个函数会触发
  activated() {
  }
};
</script>

<style scoped>
.cell-tool {
  height: 32px;
  line-height: 32px;
  padding: 0 7px;
}

.cell-player {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.cell-player-4 {
  width: 50%;
  height: 50% !important;
  box-sizing: border-box;
}

.cell-player-1 {
  width: 100%;
  box-sizing: border-box;
}

.cell-player-6-1 {
  width: 66.66%;
  height: 66.66% !important;
  box-sizing: border-box;
}

.cell-player-6-2 {
  width: 33.33%;
  height: 66.66% !important;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}

.cell-player-6-none {
  display: none;
}

.cell-player-6-2-cell {
  width: 100%;
  height: 50% !important;
  box-sizing: border-box;
}

.cell-player-6 {
  width: 33.33%;
  height: 33.33% !important;
  box-sizing: border-box;
}

.cell-player-9 {
  width: 33.33%;
  height: 33.33% !important;
  box-sizing: border-box;
}

.cell-player-16 {
  width: 25%;
  height: 25% !important;
  box-sizing: border-box;
}

.cell-player-select {
  border: 1px solid #d52121;
}

.cell {
  display: flex;
  flex-direction: column;
  height: 100%;
}


</style>
<style scoped lang="scss">
::v-deep {
  .player-panel {

    height: 100%;
    display: flex;
    flex-direction: column;
    position: relative;

    &:hover {
      .ptz-panel, .definition {
        display: block;
      }
    }

    .title {

      color: white;
      position: relative;
      top: 0;
      left: 0;
      text-align: center;
      width: 100%;
      background: #1890ff;
      height: 30px;
      line-height: 30px;
    }

    .definition {
      position: absolute;
      top: 35px;
      left: 5px;
      z-index: 5;
      display: none;

      .el-radio {
        color: white;
      }
    }

    .ptz-panel {
      position: absolute;
      z-index: 5;
      top: 40px;
      right: 20px;
      display: none;
    }

    .player {
      background-color: black;
      flex: 1;
      border: 1px solid white;
      color: white;
      text-align: center;
      overflow: hidden;
    }


  }

  .ptz {
    .outer-ring {
      position: relative;
      width: 150px;
      height: 150px;
      background-color: #fff;
      border-radius: 50%;
      box-shadow: inset 0 0 25px #e8e8e8, 0 1px 0 #c3c3c3, 0 2px 0 #c9c9c9, 0 2px 3px #333;

      i {
        font-size: 20px;
        color: #606266;
        cursor: pointer;

        :hover {
          color: #00B176
        }
      }
    ;
    }

    .el-icon-caret-top {
      position: absolute;
      top: 6px;
      left: 75px;
      margin-left: -10px;
    }

    .el-icon-caret-bottom {
      position: absolute;
      bottom: 6px;
      left: 75px;
      margin-left: -10px;
    }

    .el-icon-caret-left {
      position: absolute;
      left: 6px;
      top: 75px;
      margin-top: -10px;
    }

    .el-icon-caret-right {
      position: absolute;
      right: 6px;
      top: 75px;
      margin-top: -10px;
    }

    .inner-ring {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 80px;
      height: 80px;
      border-radius: 50%;
      background-color: #fff;
      border: 1px solid #ddd;
    }

    .el-icon-plus {
      position: absolute;
      top: 10px;
      left: 40px;
      margin-left: -10px;
    }

    .line {
      height: 1px;
      width: 100%;
      background-color: #ddd;
      position: absolute;
      top: 39px;
      left: 0;
    }

    .el-icon-minus {
      position: absolute;
      bottom: 10px;
      left: 40px;
      margin-left: -10px;
    }
  }
}

</style>

ptz.vue

<!--
视频云台控制组件
-->
<template>
  <div class="ptz" ref="ptz">
    <div class="outer-ring">
      <!-- 上 -->
      <i class="el-icon-caret-top" @click="ptzController(0)"/>
      <!-- 下 -->
      <i class="el-icon-caret-bottom" @click="ptzController(1)"/>
      <!-- 左 -->
      <i class="el-icon-caret-left" @click="ptzController(2)"/>
      <!-- 右 -->
      <i class="el-icon-caret-right" @click="ptzController(3)"/>
      <div class="inner-ring">
        <i class="el-icon-plus" @click="ptzController(8)"/>
        <div class="line"></div>
        <i class="el-icon-minus" @click="ptzController(9)"/>
      </div>

    </div>
  </div>
</template>


<script>

// 云台控制接口
import {ptzControl} from "@/api/smart-real/cam";

export default {
  name: "video-ptz",
  // import引入的组件需要注入到对象中才能使用
  components: {},
  // 传递参数
  props: {
    ptzParams: {
      type: Object,
      default: null
    }
  },

  // 这里存放数据
  data() {
    return {
      isLoading: false,
    };
  },
  // 生命周期 - 创建完成(可以访问当前this实例)
  created() {

  },
  // 监听属性 类似于data概念
  computed: {},
  // 监控data中的数据变化
  watch: {},
  // 方法集合
  methods: {
// 云台控制
    ptzController(conno) {
      const options = {
        target: this.$refs.ptz,
        background: '#ffffff70'
      }
      const loading = this.$loading(options)
      let data = {
        ...this.ptzParams,
        protocol: 4,
        direction: conno,
        // speed: 1
      }
      ptzControl(data).then(res => {
        setTimeout(() => {
          loading.close()
        }, 1000 * 5)
      }).catch(e => {
        loading.close()
      })
    }
  },
  // 生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {

  },
  // 生命周期 - 销毁之前
  beforeDestroy() {
  },
  // 如果页面有keep-alive缓存功能,这个函数会触发
  activated() {
  }
};
</script>

<style scoped lang="scss">

</style>

cellPlayer.vue
需要安装 npm i nanoid
VideoPlayUtils 我封装的播放视频的js使用的是flv.js

<!--
视频播放组件
-->
<template>
  <div class="player-panel">
    <div class="title">{{ title }}</div>
    <div class="definition" v-if="ptzParams && ptzParams.id">
      <el-radio v-model="definition" :disabled="disableSharpness" :label="1">高清</el-radio>
      <el-radio v-model="definition" :disabled="disableSharpness" :label="2">流畅</el-radio>
    </div>
    <ptz class="ptz-panel" v-if="ptzParams && ptzParams.ptzControlOrNot" :ptz-params="ptzParams"></ptz>
    <component :is="videoTag" :id="videoId" class="player" controls="controls">

    </component>
  </div>


</template>


<script>
import ptz from './ptz.vue'
// 生成uuid
import {nanoid} from 'nanoid'
import {camVideoClose, getFlvJsPlayer} from '@/utils/VideoPlayUtils'

export default {
  name: "video-panel",
  // import引入的组件需要注入到对象中才能使用
  components: {
    ptz
  },
  // 传递参数
  props: {
    // 视频标题
    title: {
      type: [String, Number],
      default: ''
    },
    // 视频标签类型
    videoTag: {
      type: String,
      default: 'div'
    },
    // 视频播放地址
    videoUrl: {
      type: String,
      default: null
    },
    accessToken: {
      type: String,
      default: null
    },
    // 云台控制参数
    ptzParams: {
      type: Object,
      default: null
    },
  },

  // 这里存放数据
  data() {
    return {
      videoId: 'video-id' + nanoid(10),
      player: null,
      // 清晰度 1高清 2流畅
      definition: 1,
      // 是否禁用清晰度
      disableSharpness: false
    };
  },
  // 生命周期 - 创建完成(可以访问当前this实例)
  created() {

  },
  // 监听属性 类似于data概念
  computed: {},
  // 监控data中的数据变化
  watch: {
    videoUrl(newVal) {
      this.playVideo()
    },
    // 改变清晰度时
    definition(newVal) {
      if (!this.ptzParams) {
        return
      }
      this.$emit('change-clarity', this.ptzParams.id, newVal)
      this.disableSharpness = true
      setTimeout(() => {
        this.disableSharpness = false
      }, 1000 * 5)
    }
  },
  // 方法集合
  methods: {
    async playVideo() {
      this.closeVideo()
      if(!this.videoUrl) {
        return
      }
      // const rect = document.getElementById(this.videoId).getBoundingClientRect()
        const player = await getFlvJsPlayer({
          source: this.videoUrl,
          id: this.videoId
        })
      this.player = player
    },
    closeVideo() {
      if (this.player) {
        camVideoClose({video: this.player})
        this.player = null
      }
    },
  },
  // 生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {
    this.playVideo()
  },
  // 生命周期 - 销毁之前
  beforeDestroy() {
    this.closeVideo()
  },
  // 如果页面有keep-alive缓存功能,这个函数会触发
  activated() {
  }
};
</script>


撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题