Vue personaliza el componente de la barra de progreso del reproductor de video h5video, que puede arrastrar, saltar, duplicar la velocidad y pantalla completa

necesidad

Un componente de barra de progreso controla la reproducción y el ajuste de progreso de múltiples videos. Se puede hacer clic en el video para verlo en pantalla completa, y la única barra de progreso es la información del video de un video específico.

icono

Una barra de progreso controla la reproducción de múltiples videos

lograr

html

//视频
 <div
        v-for="(item, index) in urls"
        :key="index"
      >
        <video :ref="item.type"  preload="auto" :src="item.url" />
        <div>
        // svg-icon是icon图标组件 
          <svg-icon v-if="!isFullScreen" :style="{ fill: '#dbdbdb', 'font-size': 20 + 'px' }" icon-class="quanping_o" @click="handleFullScreen(item)" />
          <svg-icon v-else :style="{ fill: '#dbdbdb', 'font-size': 20 + 'px' }" icon-class="quxiaoquanping_o" @click="handleFullScreen(item)" />
        </div>
      </div>
//进度条
 <div v-show="fileUrl" class="progress-wrap">
        <div class="operate">
          <div class="speed">
          //倍速列表
            <el-menu class="list" mode="horizontal">
              <el-menu-item v-for="(speed, i) in speedList" :key="i" class="list-item" @click="handleChangeSpeed(speed)">{
   
   { speed }}</el-menu-item>
            </el-menu>
            //显示倍速
            {
   
   { playSpeed }}x
          </div>
          <div>
            <div class="play-wrap" @click="play">
              <svg-icon v-if="!paused" icon-class="zanting" :style="{ 'font-size': 14 + 'px' }" />
              <svg-icon v-else-if="paused" icon-class="bofang" :style="{ 'font-size': 14 + 'px' }" />
            </div>
            // 显示已播放时长和总时长
            <div class="timer">{
   
   { currentTime }} / {
   
   { totalTime }}</div>
          </div>
        </div>
//进度条容器
        <div ref="control" class="control" @click="adjustProgress($event)">
        // 进度条本条
          <div class="progress" :style="{ width: progressWidth }">
          //滑块
            <div class="slider_circle" @mousedown="handleSliderMouseDown" />
            <div class="slider_circle_large" />
          </div>
        </div>
      </div>

vue.js

pantalla completa

 handleFullScreen(item) {
    
    
      this.isFullScreen = !this.isFullScreen //isFullScreen 定义为布尔值,控制样式用的,给视频容器高度设置为100vh,宽度100%实现全屏显示
      this.fullVideoType = item.type  //控制样式用的,不必要
    },

Haga clic en la barra de progreso para saltar

inserte la descripción de la imagen aquí

 adjustProgress(e) {
    
    
      e.preventDefault()
      // 这里的this.controlRef = this.$refs.control,加载完视频后定义即可
      const {
    
     left, width } = this.controlRef.getBoundingClientRect()
      // left: 进度条容器control到最左侧的距离,width:容器的宽度
        // e.clientX:鼠标点击的位置到最左侧的距离
      const progressWidth = e.clientX - left
      this.progressWidth = progressWidth + 'px'
      this.updadteCurrentTime(progressWidth, width)
    },

arrastre el control deslizante

Hay explicaciones detalladas de los siguientes parámetros en el tutorial de novato. Olvidé dónde mirar esta imagen. Si lo reclama, comente y publicaré el enlace.
inserte la descripción de la imagen aquí

  handleSliderMouseDown(event) {
    
    
  //如果不添加以下两处的阻止默认事件,会出现以下情况: 鼠标点击滑块向前拉动,移出进度条范围时,会自动选择文字等元素,出现禁用图标。松开鼠标,再次进入进度条,即使没有按住滑块,滑块也会跟随鼠标移动。这不是我们想要看到的效果。
      event.preventDefault()
      // 滑块点击坐标
      const offsetX = event.offsetX
      document.onmousemove = (e) => {
    
    
        e.preventDefault()
        // 滑动距离可视区域左侧的距离
        const X = e.clientX
        // 减去滑块偏移量
        const cl = X - offsetX
        const {
    
     left, width } = this.controlRef.getBoundingClientRect()
        // 除去滑块按钮长度的进度条长度
        const ml = cl - left
        let progressWidth
        if (ml <= 0) {
    
    
        //进度条长度最小和最大值的界定
          progressWidth = 0
        } else if (ml >= width) {
    
    
          progressWidth = width
        } else {
    
    
          progressWidth = ml
        }
        this.progressWidth = progressWidth + 'px'
        // 更新当前时间
        this.updadteCurrentTime(progressWidth, width)
      }
//抬起鼠标,结束移动事件
      document.onmouseup = () => {
    
    
        document.onmousemove = null
        document.onmouseup = null
      }
    },

doble velocidad

// 倍速
handleChangeSpeed(item) { this.playSpeed ​​= item },

reproducir pausar

 play() {
    
    
 //是否暂停
      this.paused = !this.paused
      // 若此刻状态是重新播放,那么点击播放时,进度条需从头开始前进
      // 进度条控制的是中间视频,this.middleRef
      if (this.middleRef.duration === this.middleRef.currentTime) {
    
    
        this.middleRef.currentTime = 0
        this.currentTime = this.formatSeconds(this.middleRef.currentTime)
        this.progressWidth = 0 + 'px !important'
      }
      if (!this.paused) {
    
    
      // 定时器实时刷新
        this.timer = setInterval(this.updateVideoProgress, 50)
        this.updateVideoProgress()
      }
      this.videoRefArr.forEach((v) => {
    
    
        v.currentTime = this.middleRef.currentTime
        if (this.paused) {
    
    
          v.pause()
        } else {
    
    
          v.play()
          // 按倍速播放
          v.playbackRate = this.playSpeed
        }
      })
    },
    clearTimer() {
    
    
      if (this.timer) {
    
    
        clearInterval(this.timer)
        this.timer = null
      }
    },
      // 更新播放时进度条长度
    updateVideoProgress() {
    
    
    //按照已播放时间和总时长的比例更新进度条长度
      this.progressWidth = (this.middleRef.currentTime / this.middleRef.duration) * 100 + '%'
      this.currentTime = this.formatSeconds(this.middleRef.currentTime)
      this.totalTime = this.formatSeconds(this.middleRef.duration)
    
      // 放完、暂停这两种情况,遍历所有视频,使他们的状态一致,并清除定时器
      if (this.middleRef.currentTime === this.middleRef.duration || this.paused) {
    
    
        this.videoRefArr.forEach((v) => {
    
    
          v.pause()
        })
        this.paused = true
        this.clearTimer()
      }
    },
    // 格式化时间 
    formatSeconds(value) {
    
    
      const result = parseInt(value)
      const h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600)
      const m = Math.floor((result / 60) % 60) < 10 ? '0' + Math.floor((result / 60) % 60) : Math.floor((result / 60) % 60)
      const s = Math.floor(result % 60) < 10 ? '0' + Math.floor(result % 60) : Math.floor(result % 60)
      //把视频时长格式化到毫秒
      let ms
      const msValue = value.toFixed(3).toString().split('.')[1]
      if (Math.floor(msValue % 1000) < 10) {
    
    
        ms = '00' + Math.floor(msValue % 1000)
      } else if (Math.floor(msValue % 1000) > 10 && Math.floor(msValue % 1000) < 100) {
    
    
        ms = '0' + Math.floor(msValue % 1000)
      } else if (Math.floor(msValue % 1000) < 1000) {
    
    
        ms = Math.floor(msValue % 1000)
      }
      let res = ''
      res += `${
      
      h}:`
      res += `${
      
      m}:`
      res += `${
      
      s}.`
      res += `${
      
      ms}`
      return res
    }

Después de saltar y arrastrar, la longitud de la barra de progreso se actualiza al actualizar el tiempo actual del video

 // 更新当前时间、帧号
    updadteCurrentTime(progressWidth, width) {
    
    
      this.currentTime = this.formatSeconds((progressWidth / width) * this.middleRef.duration)
      this.totalTime = this.formatSeconds(this.middleRef.duration)
      this.videoRefArr.forEach((v) => {
    
    
        v.currentTime = (progressWidth / width) * this.middleRef.duration
      })
    },

Resumen: dicho componente debe escribirse para uso interno en la empresa. Aunque menos general, es más flexible. La estructura html omite los estilos relevantes en aras de una visualización intuitiva.

Aquellos que estén interesados ​​pueden discutir juntos.

La originalidad no es fácil, publique la fuente para la reimpresión

Supongo que te gusta

Origin blog.csdn.net/huangyinzhang/article/details/125183579
Recomendado
Clasificación