记录工作中遇到的问题

需求:点击播放按钮显示弹层,在弹层上播放m3u8格式的音频流 

效果如下:

点击父组件的播放按钮

弹层显示出来,播放音频流(背景图片是我自己加的)

使用步骤: 

1.安装video.js和videojs-contrib-hls

npm i video.js
npm i videojs-contrib-hls

2.组件中引入

import videojs from 'video.js'
import 'video.js/dist/video-js.css'
import 'videojs-contrib-hls'

3.准备一个video容器

<video
 id="my-video"
 class="video-js vjs-default-skin vjs-big-play-centered"
 controls
 preload="auto"
 style='width: 100%;height: auto'
 :poster="poster"
 ></video>

4.初始化video.js(此处可以进行播放器的配置网上有很多)

methods:{
// 初始化videojs
    getVideo () {
      this.myVideo = videojs(
        'my-video',
        {
          // autoplay: false, // 自动播放
          // loop: true, // 循环播放
          controls: true, // 控制元件
          width: 500, // 视频播放器显示的宽度
          height: 300, // 视频播放器显示的高度
          preload: 'none',
          bigPlayButton: true,
          posterImage: false,
          textTrackDisplay: false,
          errorDisplay: false,
          controlBar: true,
          sources: [{
            src: this.audioSrc,
            type: 'application/x-mpegURL'
          }]
        },
        function () {
          this.play()
        }
      )
    }
}

// 一进来就调用方法初始化video.js
mounted() {
    this.getVideo()
}

我的代码 :

1.子组件(弹层)代码

<template>
  <!-- 此处显示隐藏使用v-show,不要用v-if -->
  <div class="modal-bg" v-show="show">
    <div class="modal-container">
      <div class="modal-header">音频播放</div>
      <hr />
      <div class="modal-main">
        <slot>
          <!-- 默认数据 -->
          <video id="my-video" class="video-js vjs-default-skin"></video>
        </slot>
      </div>
      <hr />
      <div class="modal-footer">
        <button @click="hideModal">关闭</button>
      </div>
    </div>
  </div>
</template>

<script>
// 需要用video.js 和 hls
import videojs from 'video.js'
import 'video.js/dist/video-js.css'
import 'videojs-contrib-hls'
import StreamApi from '@/api/stream'

export default {
  props: {
    show: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      // 配置项
      myVideo: null,
      audioSrc: 'http://208.241.129.64:8080/live/output.m3u8'
    }
  },
  methods: {
    async getUrl () {
      const { data } = await StreamApi.GetUrl.post()
      console.log('获取流地址: ', data.streamUrl)
    },
    // 取消
    hideModal () {
      // 关闭弹层,销毁videojs
      this.$emit('hideModal')
      this.myVideo.dispose()
    },
    // 初始化videojs
    getVideo () {
      this.myVideo = videojs(
        'my-video',
        {
          // autoplay: false, // 自动播放
          // loop: true, // 循环播放
          controls: true, // 控制元件
          width: 500, // 视频播放器显示的宽度
          height: 300, // 视频播放器显示的高度
          preload: 'none',
          bigPlayButton: true,
          posterImage: false,
          textTrackDisplay: false,
          errorDisplay: false,
          controlBar: true,
          sources: [{
            src: this.audioSrc,
            type: 'application/x-mpegURL'
          }]
        },
        function () {
          this.play()
        }
      )
    }
  }
}
</script>

<style lang="less" scoped>
// 弹层样式
/deep/ #my-video {
  background-image: url('~@/assets/audio-img.png');
  background-repeat: no-repeat;
  background-size: contain;
  /*兼容浏览器版本*/
  -webkit-background-size: contain;
  -o-background-size: contain;
  background-size: contain;
  z-index: 99;
}
// 隐藏掉一个报错按钮不让点击
/deep/ .vjs-picture-in-picture-control {
  display: none !important;
}
// 遮罩
.modal-bg {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  z-index: 10;
}
// 内容
.modal-container {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: #fff;
  border-radius: 6px;
  overflow: hidden;
  // min-width: 710px;
  // min-height: 520px;
}
.modal-header {
  padding-left: 30px;
  height: 55px;
  line-height: 60px;
  font-size: 16px;
}
.modal-footer {
  display: flex;
  align-items: center;
  padding-left: 480px;
  height: 55px;
}
.modal-footer button {
  margin-bottom: 10px;
  width: 80px;
  height: 33px;
}
.modal-main {
  min-height: 366px;
  padding: 33px 55px;
}
</style>

2.父组件代码

<!-- 音频播放按钮 -->
<a @click="play()">播放</a>
<!-- 音频播放组件(弹层) -->
<AudioModal ref="audio" :show="show" title="音频播放" @hideModal="show = false">
    <div ref="myBox"></div>
</AudioModal>
methods: {
    // 播放
    play () {
      // 打开弹层
      this.show = true
      // 准备video容器
      this.$refs.myBox.innerHTML = '<video id="my-video" class="video-js vjs-default-skin"></video>'
      // 点击时调用子组件内的方法,初始化video.js
      this.$refs.audio.getVideo()
      // 调用方法获取流地址
      this.$refs.audio.getUrl()
    }
}

我遇到的报错:Uncaught (in promise) TypeError: The element or ID supplied is not valid. (videojs)

在我们正常使用的时候都是完全可以使用的,但是当我们有的时候需要把视频放在弹窗el-dialog里面显示时,可能会出现这个报错问题。

原因:刚进来时页面未找到相应组件,此时调用初始化video.js的方法就报错

解决:使用setTimeout延迟加载。如下:

let _that = this;
setTimeout(() => {
	 _that.getVideo();
}, 300);

但是在使用他的方法后我的问题并没有解决。

然后我就自己找了个简单的弹层,将弹层的显示隐藏改为v-show,然后在父组件播放按钮的点击事件里调用子组件的初始化video.js的方法 getVideo()。

 参考文章:范特西是只猫https://blog.csdn.net/qq_36410795/article/details/107109514

lucky-peachhttps://blog.csdn.net/little__SuperMan/article/details/89203270

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐