今天看啥  ›  专栏  ›  张宇杭

vue项目中,采坑自定义video视频控制条

张宇杭  · 掘金  ·  · 2020-04-25 16:46
阅读 30

vue项目中,采坑自定义video视频控制条

背景


最近公司项目中,添加了视频模块,但是产品觉得Video自带的控制条有点LOW,于是自己设计了一个。于是开始了自定义Video控制的采坑之旅。。

首页效果图:

需求描述:

当鼠标放在图片上的时候,自动播放视频,并显示预览进度条,当鼠标移开,显示预览图片,再次hover图片,继续上次播放

视频详情页的效果图:

需求描述:

  • 能自定义的暂停和播放
  • 模仿进度条可实现拖拽播放速度
  • 显示当前时间
  • 能选择倍速
  • 能控制声音
  • 能全屏播放

接下来一步步的实现

首先康康首页的,上结构代码:

               <div class="clickL video-box" @mouseover="play(item3.images_id)" @mouseout="pause(item3.images_id)">
                    <img v-lazy="item3.picture" width="268" alt="" v-show="id != item3.images_id">
                    <video class="video-hover" ref="videoAll" onMouseOver="this.play()" :src="item3.short_video" @timeupdate="commonVideoUpdata(index)" width="268px" height="176px" onMouseOut="this.pause()" muted loop="loop">
                    </video>
               </div>
                <div class="process-slider common-progress" v-show="id == item3.images_id">
                      <el-slider v-model="currentTimeProgress" :show-tooltip="false" input-size="small"></el-slider>
                </div>
复制代码

这里思路是:

1,判断用户鼠标事件,切换图片和视频。

2.video需要通过video来获取他实例来进行dom操作,video的鼠标移入和滑出分类是控制视频的播放和停止,play和pause是video的内置方法。更多方法见这里哦~

3.这里的进度条使用的是element的滑动条组件,默认max是100,显示视频的时候,这里用v-show判断显隐。

css部分代码:

      .video-box {
            position: relative;
            height: 176px;

            &>img {
                width: 100%;
                height: 100%;
                position: absolute;
                left: 0;
                top: 0;
                z-index: 2;
            }

            &>video {
                object-fit: fill; //拉伸填充盒子,保证和图片一样大
            }

        }
复制代码

css部分主要是要注意让video显示的时候和图片的宽高一致,不然就会出现图片大,视频小的情况,如图:

逻辑部分:

data() {
     return {
       id:0, //保存当前播放的视频id
      currentTimeVal:0 //进度条
    }
},
methods:{
    //开始播放
    play(val) {
        this.id = val
        },
     // 停止播放,显示图片清零进度条
    pause(val) {
        this.id = 0
        this.currentTimeVal = 0
    },
       // 公共video获取时间
        commonVideoUpdata(id) {
            let videoObj = this.$refs.videoAll
            console.log(videoObj);
            let currTime = videoObj[id].currentTime //当前时间
            let duration = videoObj[id].duration //总时间
            let pre = currTime / duration
            this.currentTimeProgress = pre * 100;
        },
}
  
复制代码

这里使用video 的timeupdate内置方法获取当前播放时间,并获取当前的的dom元素,这里的videoObj打印出来是个数组:

我们通过当前元素在数组中循环出来的索引来获取对应视频的时间,最后一个简单的计算进度条的方法,(当前时间 / 总时间)* 100 = 进度条的值
注意坑点:如果在数组中掺杂了其他的非视频文件,这里使用ref的方式,就不能根据索引来获取,就得定义唯一的ref,嘿嘿!

到此首页功能结束了,接着实现详情页的自定义控制条。

html部分:

 <div class="detali_box_img video-media">
                <div class="video-example">
                  <video :src="item.video_file" width="100%" height="100%" loop="loop" preload="auto" @timeupdate="videoTimeUpdate" @click="controlVideo" ref="videoCon">
                    您的浏览器不支持 video 标签。
                  </video>
                </div>
                //视频中的暂停按钮
                <div class="play-btn" @click="controlVideo" :style="[opcityVal]"></div>
                // 控制条的播放和暂停按钮
                <div class="control-play">
                  <p class="control-play-btn" @click="controlVideo">
                    <span class="el-icon-video-play" v-show="!vcIsPlay"></span>
                    <span class="el-icon-video-pause" v-show="vcIsPlay"></span>
                  </p>
                  //播放进度条
                  <div class="control-progress common-progress">
                    <div>
                      <el-slider v-model="vcProgress" :show-tooltip="false" :max="durationProgress" input-size="small" @change="getNewTime"></el-slider>
                    </div>
                    <!-- <p class="control-progress-item"></p> -->
                  </div>
                  //当前播放时间
                  <div class="current-time">{{vcCurrentTime}}</div>
                  //视频总时长
                  <div class="duration">{{item.duration_time}}</div>
                  //倍速控制
                  <div class="video-speed-box" @click="getPlayBackRate">
                    <el-dropdown placement="bottom" @command="handleCommand">
                      <!-- <span class="el-dropdown-link"> -->
                      <span class="video-speed-show">{{speedTime}}</span>
                      <!-- </span> -->
                      <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item command="1">0.5x</el-dropdown-item>
                        <el-dropdown-item command="2">1x</el-dropdown-item>
                        <el-dropdown-item command="3">1.5x</el-dropdown-item>
                        <el-dropdown-item command="4">2x</el-dropdown-item>
                        <el-dropdown-item command="5">3x</el-dropdown-item>

                      </el-dropdown-menu>
                    </el-dropdown>

                  </div>
                  //音量控制
                  <div class="control-voice common-progress">
                    <span class="voice-icon"></span>
                    <div class="voice-slider">
                      <el-slider v-model="voiceProgress" input-size="small" @change="getNewVoice"></el-slider>
                    </div>
                  </div>
                  //全屏播放
                  <p class="fullscreen" title="全屏" @click="getFullSceen">
                    <span class="el-icon-full-screen"></span>
                  </p>
                </div>
              </div>
复制代码

css部分忽略了。。。
直接看功能: 首先data部分:

      vcIsPlay: false, //是否播放
      opcityVal: {
        opacity: '1'
      },
      currentTimeVal: 0, // 当前时间
      vcCurrentTime: '00:00:00', //当前时间格式化
      vcProgress: 0, //进度条的绑定时间
      durationProgress: 0, //当前视频的总时长
      speedTime: '1x', //倍速
      voiceProgress: 0 //声音
复制代码

暂停和播放:

  // 播放和暂停视频
    controlVideo() {
      let videoObj = this.$refs.videoCon
      this.durationProgress = videoObj[0].duration //总时间
      if (this.vcIsPlay) {
        videoObj[0].pause()
      } else {
        videoObj[0].play()
      }
      this.vcIsPlay = !this.vcIsPlay
      this.opcityVal.opacity = this.opcityVal.opacity == '1' ? '0' : '1'
    },
复制代码

直接调用提供的两个方法即可,然后使用vue的style绑定控制暂停按钮的显隐即可,这里的进度条,我换了种玩法,同样是element的滑动条组件,只不过max值我换成了总时长,单位秒,原因请耐心看下文,嘿嘿!

进度条部分:

    // 获取时间
    videoTimeUpdate() {
      let videoObj = this.$refs.videoCon
      let currTime = videoObj[0].currentTime //当前时间
      this.vcProgress = currTime  //赋值给进度条
      this.vcCurrentTime = this.getFormatVideoTime(currTime)
      console.log(this.vcCurrentTime) //"00:00:27"
    },
        //格式化时间
    getFormatVideoTime(time) {
      let curtime = time
      let h = parseInt(curtime / 3600)
      let m = parseInt((curtime % 3600) / 60)
      let s = parseInt(curtime % 60)
      h = h < 10 ? '0' + h : h
      m = m < 10 ? '0' + m : m
      s = s < 10 ? '0' + s : s
      return h + ':' + m + ':' + s
    },
复制代码

这里难点是,我如何进行拖动进度条,来进行控制呢?
别慌,看代码:

@change="getNewTime" //element 的滑动组件有个chang事件
   getNewTime(val) {
      let videoObj = this.$refs.videoCon
      console.log(val)
      videoObj[0].currentTime = val
    },
复制代码

通过change进度条,然后重新赋值给当前时间就搞定了,可以说是炒鸡舒服了

倍速部分:

 // 获取当前播放的速度
    handleCommand(val) {
      let videoObj = this.$refs.videoCon
      switch (val) {
        case '1':
          videoObj[0].playbackRate = 0.5
          this.speedTime = '0.5x'
          break
        case '2':
          videoObj[0].playbackRate = 1
          this.speedTime = '1x'
          break
        case '3':
          videoObj[0].playbackRate = 1.5
          this.speedTime = '1.5x'
          break
        case '4':
          videoObj[0].playbackRate = 2
          this.speedTime = '2x'
          break
        case '5':
          videoObj[0].playbackRate = 3
          this.speedTime = '3x'
          break

        default:
          videoObj[0].playbackRate = 1
          this.speedTime = '1x'
          break
      }
    },
复制代码

看图:

这里使用的是element的下拉组件,同样,Video的playbackRate可以直接赋值,控制播放速度

声音部分:

    // 设置声音

    getNewVoice(val) {
      let videoObj = this.$refs.videoCon
      let newVc = val / 100 //h5规定,volume的值必须再0-1之间,比如0.5就是50%的音量,但是进度条的值为100,因此这里做个除法
      videoObj[0].volume = newVc //赋值
    },
复制代码

我也是使用的滑组件,max值保持默认的100,然后滑动改变的时候,把默认值除100,比如当前滑块的新值是50,除100后得到的就是【0-1】范围里的合法值,Video提供的volume值如果不在 0-1之间,就会报错

最后是全屏部分:

    // 全屏播放
    getFullSceen() {
      let videoObj = this.$refs.videoCon
      videoObj[0].webkitRequestFullScreen()
    },
复制代码

但是我看到网上还有一种方法是模拟按下f11的全部,如果有兴趣也可以了解下!

总结

因为之前没有很仔细的搞过video,所以对它很多的内置属性和方法不了解,没经验就害怕,很慌很慌,这就跟谈恋爱似的,哈哈哈,再组长的支持和鼓励下,我大胆的尝试了,成功后,这次经验给了我很大信心,感觉以后写其他没做过的功能,都不会慌了,毕竟难的部分写elementUi的大佬们都给写好了,可以说是站在巨人的肩膀上,哈哈哈!膜拜大佬,以后还得多多努力了。




原文地址:访问原文地址
快照地址: 访问文章快照