video重写控制条——解决video全屏层级最高问题

4,470 阅读4分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

@[toc] 全屏video会在最上层,这个时候设置定位或者z-index都是无效的,按照有些博客中的z-index设置成2147483647也没用,x5-video-player-type="h5"也没用,于是决定重写控制条。 经过分析,简单的重写控制条的话,有这么几个功能点: 1.暂停功能/播放功能

  • 播放时进度条跟随功能
  • 播放时时间改变功能
  • 暂停时进度条停止功能
  • 暂停时时间停止功能 2.全屏功能
  • 进入全屏
  • 退出全屏 3.当前时间和总时间的显示
  • 播放的当前时间
  • 播放的总时间 4.进度条拖动功能
  • 进度条拖动时画面跳转功能
  • 进度条拖动时时间跟随变化功能 5.播放结束时的处理

一、页面的HTML部分

<!-- @contextmenu.prevent="" 禁止右键菜单 -->
<div class="relative" @contextmenu.prevent="">
        <div class="content">
          <div class="player">
            <video 
              preload="auto"
              webkit-playsinline="true"
              playsinline="true"
              x-webkit-airplay="allow"
              x5-video-player-type="h5"
              x5-video-player-fullscreen="true"
              style="object-fit: fill"
              :src="src"
            >
              您的浏览器不支持 video 标签。
            </video>
            <div class="control">
              <div
                class="iconfont iconfa-play play_pause"
                @click="handlePlay"
              ></div>
              <div>
                <el-slider
                  v-model="progressValue"
                  class="progress"
                  @change="handleChangeProgress"
                ></el-slider>
              </div>
              <div class="timer">
                <span class="progress_timer">00:00:00</span>/
                <span class="duration_timer">00:00:00</span>
              </div>
              <div
                class="iconfont iconexpand expand"
                @click="handleSreen"
              ></div>
            </div>
            <img
              v-watermark="{
                text: baseParamPressimg,
                textColor: 'rgb(180, 180, 180)',
              }"
              class="baseParamPressimg"
              @click="handleImg"
            />
          </div>
        </div> 
      </div>

二、css部分

/*video样式*/
/deep/.video-box {
  overflow: hidden;
  background: #000;
  width: 750px;
  display: block;
  margin: 0 auto;
  -webkit-transition-duration: 300ms;
  -moz-transition-duration: 300ms;
  -ms-transition-duration: 300ms;
  -o-transition-duration: 300ms;
  transition-duration: 300ms;
  z-index: 10;
}
/deep/.video-box-body {
  width: 100%;
  height: 422px;
  overflow: hidden;
  position: relative;
}
/deep/.video-body {
  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 15;
}
/*video样式*/
/deep/.video-box {
  overflow: hidden;
  background: #000;
  width: 750px;
  display: block;
  margin: 0 auto;
  -webkit-transition-duration: 300ms;
  -moz-transition-duration: 300ms;
  -ms-transition-duration: 300ms;
  -o-transition-duration: 300ms;
  transition-duration: 300ms;
  z-index: 10;
}
/deep/.video-box-body {
  width: 100%;
  height: 422px;
  overflow: hidden;
  position: relative;
}
/deep/.video-body {
  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 15;
}
// /deep/.vjs-text-track-display {
//   width: 657px;
//   height: 290px;
// }
/deep/.video-js {
  /deep/.vjs-control-bar {
    .vjs-icon-custombutton {
      font-family: VideoJS;
      font-weight: normal;
      font-style: normal;
    }
    .vjs-icon-custombutton:before {
      content: "\f108";
      font-size: 1.8em;
      line-height: 1.67;
    }
  }
}
* {
  margin: 0;
  padding: 0;
}
/* 去掉全屏时显示的自带控制条 */
video::-webkit-media-controls {
  display: none !important;
}
.wrap h3 {
  text-align: center;
  height: 100px;
  line-height: 100px;
}
.player {
  width: 720px;
  height: 400px;
  margin: 0 auto;
  position: relative;
}
.player video {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  height: 100%;
}
.control {
  display: flex;
  align-items: center;
}
.player .control {
  position: absolute;
  width: 100%;
  height: 40px;
  border-radius: 5px;
  left: 50%;
  bottom: 10px;
  transform: translateX(-50%);
  z-index: 999;
}
.player .control div {
  display: inline-block;
  line-height: 40px;
  margin-left: 10px;
  font-size: 18px;
  color: #fff;
}
.player .control .play_pause,
.player .control .expand {
  color: rgb(255, 255, 0);
}
.player .control div:nth-child(2) {
  width: 460px;
  height: 12px;
  background-color: rgba(255, 255, 255, 0.8);
  overflow: hidden;
  flex: 1;
  margin: 0 10px;
}
.player .control .progress {
  display: block;
  width: 100%;
  height: 12px;
  background: $grade;
  margin-left: 0;
}
.player .control .timer {
  font-size: 12px;
}
.expand {
  width: 50px;
}
/deep/.el-tooltip {
  vertical-align: super;
}
/deep/.el-slider__button {
  border: none;
  width: 10px;
  height: 10px;
  margin: 0 10px;
}
/deep/.el-slider__button-wrapper {
  height: 0;
}
.baseParamPressimg {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 99;
  width: 100%;
  height: 100%;
}

三、暂停功能/播放功能

handlePlay() {
      console.log("播放");
      // 获取元素
      var videoObj = document.querySelector("video");
      var playBtn = document.querySelector(".play_pause");
      if (videoObj.paused) {
        // 如果视频处于播放状态
        videoObj.play();
        playBtn.classList.remove("iconfa-play");
        playBtn.classList.add("iconfa-pause");
      } else {
        videoObj.pause();
        playBtn.classList.add("iconfa-play");
        playBtn.classList.remove("iconfa-pause");
      }
      this.myTime = setInterval(() => {
        vm.handleChangeTime();
        //结束时的事件
        if (this.progressValue == 100) {
          //清除定时器
          clearInterval(this.myTime);
          //进度条重置为0
          this.progressValue = 0;
          //停止播放
          videoObj.pause();
          playBtn.classList.add("iconfa-play");
          playBtn.classList.remove("iconfa-pause");
        }
      }, 1000);
    },

四、全屏功能

//实现全屏
    handleSreen() {
      // 0.实现全屏
      if (!this.videoState) {
        document.querySelector(".player").webkitRequestFullScreen();
        this.videoState = 1;
      } else {
        document.webkitCancelFullScreen();
        this.videoState = 0;
      }
    },

五、当前时间和总时间的显示

//实现时间
    handleChangeTime() {
      var videoObj = document.querySelector("video");
      var progressTimer = document.querySelector(".progress_timer");
      var durationTimer = document.querySelector(".duration_timer");
      let { totalT, presentT } = { totalT: 0, presentT: 0 };
      totalT = videoObj.duration;
      var videoDuration = vm.formatTime(totalT);
      durationTimer.innerHTML = videoDuration;
      presentT = videoObj.currentTime;
      var videoCurrent = vm.formatTime(presentT);
      progressTimer.innerHTML = videoCurrent;
      this.totalT = totalT;
      //进度条跟随部分
      // var progress = document.querySelector(".progress");
      this.percent = (presentT / totalT) * 100;
      this.progressValue = this.percent;
    },
    //时间格式化
    formatTime(t) {
      var h = parseInt(t / 3600);
      h = h < 10 ? "0" + h : h;
      var m = parseInt((t % 3600) / 60);
      m = m < 10 ? "0" + m : m;
      var s = parseInt(t % 60);
      s = s < 10 ? "0" + s : s;
      return h + ":" + m + ":" + s;
    },

六、进度条拖动功能

这里需要求出当前的时间,让当前的时间跟随滚动条的拖动发生改变。 当前的时间 = 拖动的数字进度 / 100 * 总时间

 handleChangeProgress() {
      // progressValue
      var videoObj = document.querySelector("video");
      videoObj.currentTime = (this.progressValue / 100) * this.totalT;
    },

七、播放结束时候的处理

此功能在第三步的代码中做了处理。

八、data部分

这里可能有缺失或者多余的参数:

	videoState: 0, //视频的播放状态 全屏1和非全屏0
      src: "", //视频的播放地址
      queryParams: {
        pageNum: 1,
        pageSize: 8,
      },
      total: 0,
      myTime: "", //当前播放的时间节点
      progressValue: 0,
      percent: 0, //当前播放和总时间之间的差值
      totalT: 0, //总时间

九、结语

效果:  参考链接:控制条功能 但是这个在全屏的时候控制条还是无法显示的状态,于是刚好看到了这篇文章 参考链接:全屏显示 于是我发现可以这样写:

document.querySelector(".player").webkitRequestFullScreen();

以上换成refs写法也是相同的 然后参考Video 对象属性和方法去改写控制条对应的功能