Vue は、ドラッグ、ジャンプ、倍速、全画面表示が可能な h5video ビデオ プレーヤーのプログレス バー コンポーネントをカスタマイズします。

必要

プログレスバーコンポーネントは、複数のビデオの再生と進行状況の調整を制御します。ビデオをクリックすると全画面で見ることができ、進行状況バーには指定したビデオのビデオ情報のみが表示されます。

アイコン

プログレスバーで複数のビデオの再生を制御します

成し遂げる

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

全画面表示

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

プログレスバーをクリックしてジャンプします

ここに画像の説明を挿入

 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)
    },

スライダーをドラッグする

以下のパラメータについてはルーキーチュートリアルに詳しく説明がありますが、この画像をどこで見るか忘れてしまいましたので、主張して​​いただけましたらリンクを貼りますのでコメントをお願いします。
ここに画像の説明を挿入

  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
      }
    },

倍速

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

再生/一時停止

 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
    }

ジャンプしてドラッグした後、ビデオの currentTime を更新することでプログレス バーの長さが更新されます。

 // 更新当前时间、帧号
    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
      })
    },

概要: このようなコンポーネントは、社内で使用するために作成する必要があります。一般的ではありませんが、より柔軟です。HTML 構造では、直感的に表示できるように、関連するスタイルが省略されています。

興味のある方は一緒に話し合っていただけます。

オリジナリティを出すのは簡単ではありません。転載する場合はソースを投稿してください

おすすめ

転載: blog.csdn.net/huangyinzhang/article/details/125183579