使用video.js重新封装视频播放器支持点播及直播

Posted 学而时习之.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用video.js重新封装视频播放器支持点播及直播相关的知识,希望对你有一定的参考价值。

一、安装指定版本是正常命令后加‘@版本号’

npm install videojs@7.15.4 --save

二,组件封装的代码

<template>
  <div class="live-video-wrapt">
    <div id="videoUpdate" class="video-show" v-show="!isError">
      <video
        id="videoTV"
        class="video-js vjs-default-skin vjs-big-play-centered vjs-16-9"
        preload="auto"
        webkit-playsinline="true"
        playsinline="true"
        type="application/x-mpegURL"
        allowsInlineMediaPlayback="YES"
        webview.allowsInlineMediaPlayback="YES"
        width="100%"
        ref="videoRef"
        x5-video-player-fullscreen="true"
        :poster="posterSrc"
        @timeupdate="onTimeupdate"
      >
        <source id="sourceBox" :src="videoSrc" ref="sourceTV" />
        <p class="vjs-no-js">不支持播放</p>
      </video>
    </div>
    <div v-show="isError" class="errorTip">
      <p>视频出错了!</p>
      <br />
      <p> textError </p>
    </div>
    <!-- 底部操作栏 -->
    <div v-show="!isError" class="tv-footer-btn">
      <div class="tv-btn tv-left">
        <!-- 播放和暂停 -->
        <div class="iconfont" v-if="tvBtnShow.stop">
          <div
            class="btn-image"
            @click="TVboting"
            :style="
              backgroundImage:
                boting === true
                  ? `url($require('./video-img/pause.png'))`
                  : `url($require('./video-img/pause-active.png'))`,
            "
          ></div>
        </div>
        <!-- 播放下一个视频 -->
        <div class="iconfont" v-if="tvBtnShow.next">
          <div
            class="btn-image"
            :style="
              backgroundImage:
                nextBtn === true
                  ? `url($require('./video-img/next.png'))`
                  : `url($require('./video-img/next-active.png'))`,
            "
          ></div>
        </div>
        <!-- 直播刷新 -->
        <div class="iconfont" v-if="tvBtnShow.update" @click="TVupdate">
          <div class="btn-image update-btn"></div>
        </div>
      </div>
      <!-- 视频进度条 -->
      <div class="tv-btn tv-centre">
        <el-slider
          class="time-progress-bar"
          v-if="tvBtnShow.bar"
          v-dragvideo
          v-model="timeVal"
          :show-tooltip="false"
          @change="onTimeChange"
          style="width: 100%"
        >
        </el-slider>
      </div>
      <div class="tv-btn tv-right">
        <!-- 音量 -->
        <div class="iconfont icon-muted" v-if="tvBtnShow.music">
          <div
            class="btn-image"
            @click="TVsound"
            :style="
              backgroundImage:
                mutedIcon === true
                  ? `url($require('./video-img/muted.png'))`
                  : `url($require('./video-img/muted-active.png'))`,
            "
          ></div>
          <div class="volume-state">
            <div class="box">
              <el-slider
                class="progress-bar"
                v-model="volumeVal"
                vertical
                :show-tooltip="false"
                @input="onMutedInput"
                height="5vw"
              >
              </el-slider>
            </div>
          </div>
        </div>
        <!-- 全屏 -->
        <div class="iconfont" v-if="tvBtnShow.full">
          <div
            class="btn-image"
            @click="TVFullScreen"
            :style="
              backgroundImage:
                fullScreen === true
                  ? `url($require('./video-img/full-screen-active.png'))`
                  : `url($require('./video-img/full-screen.png'))`,
            "
          ></div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
/* eslint-disable */
import videojs from "video.js";
import video_zhCN from "video.js/dist/lang/zh-CN.json";
import video_en from "video.js/dist/lang/en.json";
import "video.js/dist/video-js.css";
import "videojs-contrib-hls";
export default 
  name: "videojs",
  created() 
    // 直播类型
    const type = this.videoSrc
      .substring(this.videoSrc.lastIndexOf(".") + 1)
      .split("?")[0];
    const t = type.toLowerCase();
    if (t === "m3u8") 
      this.tvBtnShow.update = true;
      this.tvBtnShow.stop = false;
      this.tvBtnShow.bar = false;
    
  ,
  mounted() 
    const that = this;
    console.log("视频地址", this.videoSrc);
    //为避免在初始化video时播放源是空的,报播放源错误,需要先给source 的src赋值
    let player = videojs("videoTV", that.playOptions, function () 
      // player.controls(false);
      // this.play();
      setTimeout(() => 
        //延时确保能监听到视频源错误
        let mediaError = this.error();
        if (mediaError != null && mediaError.code) 
          that.textError = mediaError.message;
          console.log("播放失败", mediaError);
          that.isError = true;
        
      , 1000);
      this.on("loadedmetadata", function () 
        // console.log("loadedmetadata---视频源数据加载完成----");
      );
      this.on("loadeddata", function () 
        // console.log("loadeddata---渲染播放画面----");
      );
      this.on("timeupdate", function (event) 
        // 监听视频播放进度,返回视频播放历史时间
        that.$emit("historyTime", parseInt(this.currentTime()));
      );
      this.on("pause", function () 
        that.boting = false;
      );
      this.on("play", function () 
        that.boting = true;
      );
      this.on("fullscreenchange", function () 
        that.fullScreen = this.isFullscreen_;
        if (player.isFullscreen()) 
          player.controls(true);
         else 
          player.controls(false);
        
      );
      this.on("ended", function () 
        that.boting = false;
        console.log("ended---结束停止---");
        that.isError = true;
      );
    );
    videojs.addLanguage("zh-CN", video_zhCN);
    videojs.addLanguage("en", video_en);
    // player.on("click", function () 
    //   console.log("点击视频");
    // ); //设置播放器宽度
  ,
  beforeDestroy() 
    const videoDom = this.$refs.videoRef; //不能用document 获取节点
    videojs(videoDom).dispose(); //销毁video实例,避免出现节点不存在 但是flash一直在执行,也避免重新进入页面video未重新声明
  ,
  directives: 
    dragvideo: 
      bind(el, binding, vnode, oldVnode) 
        const els = el.querySelector(".el-slider__button-wrapper");
        els.addEventListener("mousedown", (e) => 
          const videoDom = videojs("videoTV");
          videoDom.ready(function () 
            let _this = this;
            _this.pause();
          );

          els.addEventListener("mouseup", (e) => 
            videoDom.ready(function () 
              let _this = this;
              _this.play();
            );
          );
        );
      ,
    ,
  ,
  props: 
    videoSrc: 
      type: String,
      required: true,
    ,
    posterSrc: 
      type: String,
      required: false,
    ,
  ,
  data() 
    return 
      timeVal: 0, // 视频进度条值
      mutedIcon: false, // 是否静音
      volumeVal: 100, // 音量进度条值
      boting: false, //是否暂停
      nextBtn: true, // 切换下一个
      fullScreen: false, //是否全屏
      tvBtnShow: 
        // 自定义操作按钮-Show
        stop: true,
        next: false,
        update: false,
        bar: true,
        music: true,
        full: true,
      ,
      playOptions: 
        autoplay: false, //自动播放
        loop: true, //循环播放
        muted: false, //是否静音
        bigPlayButton: true,
        textTrackDisplay: true,
        posterImage: true,
        errorDisplay: false,
        playbackRates: false,
        // controls: true, //是否拥有控制条
        // controlBar: false, //关闭默认控制条
        controlBar: 
          // 设置控制条组件
          /* 设置控制条里面组件的相关属性及显示与否
          'currentTimeDisplay':true,
          'timeDivider':true,
          'durationDisplay':true,
          'remainingTimeDisplay':false,
          volumePanel: 
            inline: false,
          
          */
          /* 使用children的形式可以控制每一个控件的位置,以及显示与否 */
          children: [
             name: "playToggle" , // 播放按钮
             name: "liveDisplay" , //直播流时,显示LIVE
            //  name: "currentTimeDisplay" , // 当前已播放时间
            //  name: "progressControl" , // 播放进度条
            //  name: "durationDisplay" , // 总时间
            // 
            //   // 倍数播放
            //   name: "playbackRateMenuButton",
            //   playbackRates: [0.5, 1, 1.5, 2, 2.5],
            // ,
            // 
            //   name: "volumePanel", // 音量控制
            //   inline: false, // 不使用水平方式
            // ,
             name: "FullscreenToggle" , // 全屏
          ],
        ,
      ,
      textError: "",
      isError: false,
    ;
  ,
  methods: 
    TVboting() 
      //播放或暂停
      let that = this;
      const videoDom = videojs("videoTV");
      videoDom.ready(function () 
        let _this = this;
        setTimeout(function () 
          if (that.boting === true) 
            _this.pause();
            that.boting = false;
           else 
            _this.play();
            that.boting = true;
          
        , 20);
      );
    ,
    TVupdate() 
      // 直播刷新
      this.$emit("TVupdate");
    ,
    onTimeupdate(event) 
      // 调整声音进度条
      this.timeVal = (event.target.currentTime / event.target.duration) * 100;
    ,
    onTimeChange(e) 
      // 声音进度条值,发生改变
      const totalTime = document.querySelector("#videoTV video").duration; // 视频总时长
      document.querySelector("#videoTV video").currentTime =
        (this.timeVal / 100) * totalTime;
      console.log("实际", (this.timeVal / 100) * totalTime);
    ,
    onMutedInput(e) 
      // 音量大小调整
      document.querySelector("#videoTV video").volume = e / 100;
      if (e !== 0) 
        this.mutedIcon = false;
       else 
        this.mutedIcon = true;
      
    ,
    TVsound() 
      // 是否静音
      this.mutedIcon = !this.mutedIcon;
      if (this.mutedIcon) 
        this.volumeVal = 0;
        document.querySelector("#videoTV video").volume = 0;
       else 
        this.volumeVal = 100;
        document.querySelector("#videoTV video").volume = 0.1;
      
    ,
    TVFullScreen() 
      // 全屏
      let player = videojs("videoTV");
      player.requestFullscreen();
      player.isFullscreen(true);
    ,
    TVsecond(time) 
      // 视频播放历史位置的时间
      document.querySelector("#videoTV video").currentTime = time;
    ,
  ,
;
</script>
<style>
/* 全屏操作栏样式 */
.live-video-wrapt .video-show .video-js .vjs-control-bar .vjs-volume-panel 
  position: absolute;
  right: 4em;

.live-video-wrapt
  .video-show
  .video-js
  .vjs-control-bar
  .vjs-fullscreen-control 
  position: absolute;
  right: 0;

/* 时间进度条 */
.live-video-wrapt .tv-footer-btn .tv-centre .el-slider .el-slider__runway 
  background-color: rgba(0, 0, 0, 0.5);
  margin: 0;

.live-video-wrapt
  .tv-footer-btn
  .tv-centre
  .el-slider
  .el-slider__runway
  .el-slider__bar 
  background-color: white;

.live-video-wrapt
  .tv-footer-btn
  .tv-centre
  .el-slider
  .el-slider__runway
  .el-slider__button-wrapper
  .el-tooltip.el-slider__button 
  width: 0.5vw;
  height: 0.5vw;
  border: 2px solid white;
  background-color: #de6f6f;

/* 声音进度条 */
.live-video-wrapt
  .tv-footer-btn
  .tv-btn
  .iconfont
  .volume-state
  .box
  .progress-bar
  .el-slider__runway 
  background-color: black;

.live-video-wrapt
  .tv-footer-btn
  .tv-btn
  .iconfont
  .volume-state
  .box
  .progress-bar
  .el-slider__runway
  .el-slider__bar 
  background-color: white;

.live-video-wrapt
  .tv-footer-btn
  .tv-btn
  .iconfont
  .volume-state
  .box
  .progress-bar
  .el-slider__runway
  .el-slider__button-wrapper
  .el-tooltip.el-slider__button 
  width: 0.5vw;
  height: 0.5vw;
  border: 2px solid white;
  background-color: #de6f6f;

</style>
<style scoped>
.live-video-wrapt 
  width: 100%;
  border-bottom: 1px solid #f0f0f0;
  position: relative;

.video-show 
  width: 100%;
  position: relative;

.video-show .video-js.vjs-playing .vjs-tech 
  pointer-events: auto;

.errorTip 
  font-size: 2rem;
  width: 100%;
  height: 100%;
  min-height: 8vw;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-content: center;

/* 底部操作栏 */
.live-video-wrapt .tv-footer-btn 
  width: 100%;
  box-sizing: border-box;
  padding: 1vw;
  display: flex;
  justify-content: space-evenly;
  position: absolute;
  left: 0;
  bottom: 10%;

.live-video-wrapt .tv-footer-btn .tv-btn 
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;


.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .btn-image 
  width: 3vw;
  height: 3vw;
  background: no-repeat scroll center;
  background-size: 3vw 3vw;
  display: flex;
  justify-content: center;
  align-items: center;

.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .update-btn 
  background-image: url(./video-img/update.png);

.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .update-btn:hover 
  background-image: url(./video-img/update-hover.png);

/* 音量进度条 */
.live-video-wrapt .tv-footer-btn .tv-btn .icon-muted 
  position: relative;

.live-video-wrapt .tv-footer-btn .tv-btn .icon-muted:hover .volume-state 
  display: block;

.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .volume-state 
  width: 3vw;
  height: 7.25vw;
  display: none;
  position: absolute;
  left: 0;
  bottom: 3vw;

.live-video-wrapt .tv-footer-btn .tv-btn .iconfont .volume-state .box 
  width: 3vw;
  height: 7vw;
  border-radius: 0.25vw;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;

/*  */
.live-video-wrapt .tv-footer-btn .tv-centre 
  width: 50%;
  align-items: center;

.live-video-wrapt .tv-footer-btn .tv-left .iconfont 
  margin-right: 1vw;

.live-video-wrapt .tv-footer-btn .tv-right .iconfont 
  margin-left: 1vw;

</style>

直播

点播 

 

文件夹结构

照片

 

 

 

 

 

 

 

 

 

 

 

以上是关于使用video.js重新封装视频播放器支持点播及直播的主要内容,如果未能解决你的问题,请参考以下文章

HTML5视频播放插件Video.js使用详解

video.js 视频播放器是不是支持 youtube 视频?

视频播放插件Video.js简单使用

video.js播放rtmp

网页中加入视频播放组件,并使用ffmpeg对视频转编码

video.js视频播放器