• vue.js3: 自定义video可拖动的进度条(vue@3.2.36)


    一,js代码:

    <template>
    <div>
      <div style="position:relative;">
    
      <video ref="homeVideo"
             style="position: absolute;  100vh; height: 100vw; left: -60vw; top:60vw;transform: rotate(90deg);"
             poster="static/video/cover.png" id="video"
             class="video" src="static/video/guotou.mp4" type="video/mp4"
             playsinline="true" webkit-playsinline="true"
             @canplay="getVideoInfo"
             @timeupdate="getCurrentInfo"
             x5-video-player-fullscreen="true" x5-video-orientation="portraint"
             loop="-1">
        <p>你的浏览器不支持video标签.</p>
      </video>
    
      <div id="controls" style="top:200px;100%;height:50px;background: rgb(255, 255, 0); position: absolute; z-index: 99;">
           <button @click="playOrPause">playOrPause</button>
           <button @click="openOrSlient">开关音量</button>
           <button @click="fullScreen">全屏</button>
           <div>
             总时长:{{duration}}
             当前位置:{{currentTime}}
           </div>
    
           <div style="100%;margin-left:10px;">
             <!-- 进度条容器 -->
             <div id="control" ref="control" class="control" @click="setProgress" @touchmove="controlMove" @touchend="controlEnd">
               <!-- 进度条本条 -->
               <div class="progress" :style="{background:'#00ff00', height:'10px', progressWidth+'px' }">
               </div>
                 <!-- 滑块 -->
                 <div class="slider_circle" :style="{left: (progressWidth-10)+'px' }" @touchstart="sliderStart" />
                 <div class="slider_circle_large" :style="{left: (progressWidth - 25)+'px' }" @touchstart="sliderStart" />
             </div>
           </div>
      </div>
    
      </div>
    </div>
    </template>
    
    <script>
    import { ref } from "vue";
    
    export default {
      name: "Video2Img",
      components: {
    
      },
      setup() {
        //video的ref
        const homeVideo = ref(null);
    
        //播放暂停
        const playOrPause = () => {
            console.log("homeVideo.value.paused:"+homeVideo.value.paused);
            if (homeVideo.value.paused == true) {
                homeVideo.value.play();
            } else {
                homeVideo.value.pause();
            }
        }
    
        //开关音量
        const openOrSlient = () => {
          console.log("muted1:"+homeVideo.value.muted);
          if (homeVideo.value.muted == true) {
            homeVideo.value.muted = false;
          } else {
            homeVideo.value.muted = true;
          }
        }
    
        //全屏
        const fullScreen = () => {
          homeVideo.value.requestFullscreen();
        }
    
        //显示总时长
        const duration = ref(0);
    
        //得到视频的时长等信息
        const getVideoInfo = () => {
          //console.log(parseInt(homeVideo.value.duration)); // 101
          //console.log(formatTime(parseInt(homeVideo.value.duration))); // 01:41
          duration.value = formatTime(parseInt(homeVideo.value.duration));
        }
    
        //显示播放到的当前时间
        const currentTime = ref(0);
    
        //滑动到位置的宽度
        const progressWidth = ref(0);
        //得到视频当前播放到哪里的信息
        const getCurrentInfo = () => {
          // 视频已经播放时长
          currentTime.value = formatTime(parseInt(homeVideo.value.currentTime));
    
          //计算得到宽度:
          let ratio = homeVideo.value.currentTime / homeVideo.value.duration;
          //console.log("ratio:"+ratio);
          let allWidth = document.getElementById('control').getBoundingClientRect().width;
          //console.log("all"+allWidth);
          progressWidth.value = allWidth * ratio;
          //console.log("progressWidth:"+progressWidth.value);
        }
    
        // 格式化时间函数
        const formatTime = (s) => {
          var t;
          if(s > -1) {
            var hour = Math.floor(s / 3600);
            var min = Math.floor(s / 60) % 60;
            var sec = s % 60;
            if(hour < 0 || hour == 0) {
              t = '';
            } else if(0 < hour < 10) {
              t = '0' + hour + ":";
            } else {
              t = hour + ":";
            }
    
            if(min < 10) {
              t += "0";
            }
            t += min + ":";
            if(sec < 10) {
              t += "0";
            }
            t += sec;
          }
          return t;
        }
    
        //设置进度条的长度
        const setProgress = (e) => {
          e.preventDefault()
          //
          const {left, width } = document.getElementById('control').getBoundingClientRect()
          // left: 进度条容器control到最左侧的距离
          //15: 按钮宽度的一半
          const proWidth = e.clientX - left
          progressWidth.value = proWidth;
    
          updadteCurrentTime(progressWidth.value, width);
        }
    
        //设置视频播放到指定的长度
        const updadteCurrentTime = (progressWidth, width) => {
          let dest = (progressWidth / width) *  homeVideo.value.duration;
          //console.log("dest:"+dest);
          homeVideo.value.currentTime = Math.floor(dest);
        }
    
        //移动的类型,用来标明是否在拖动进度条
        const moveType = ref("");
        //拖动开始时点击的位置
        const moveOffsetX = ref(0);
        //拖动开始时进度条的宽度
        const curWidth = ref(0);
        //当开始触摸开始在圆点按下时
        const sliderStart = (e) => {
            e.preventDefault();
          moveOffsetX.value = e.touches[0].clientX;
          moveType.value = "slider";
          curWidth.value = progressWidth.value;
        }
    
        //当触摸在controls上移动时
        const controlMove = (e) => {
          if (moveType.value !== 'slider') {
            return false;
          }
          e.preventDefault()
          // 滑动距离可视区域左侧的距离
          const X = e.touches[0].clientX
          //得到本次拖动已经过的距离
          const cl = X - moveOffsetX.value;
          //容器的宽度
          const {width } = document.getElementById('control').getBoundingClientRect()
          //得到已拖动到的宽度
          const ml =  curWidth.value + cl
          let proWidth
          if (ml <= 0) {
            //进度条长度最小和最大值的界定
            proWidth = 0
          } else if (ml >= width) {
            proWidth = width
          } else {
            proWidth = ml
          }
          progressWidth.value = proWidth;
          // 更新当前时间
          updadteCurrentTime(progressWidth.value, width);
        }
    
        //滑动结束
        const controlEnd = () => {
          moveType.value = "";
        }
    
        return {
          homeVideo,
          playOrPause,
          openOrSlient,
          fullScreen,
          getVideoInfo,
          duration,
          getCurrentInfo,
          currentTime,
          progressWidth,
          setProgress,
          //拖动
          sliderStart,
          controlMove,
          controlEnd,
        }
      }
    }
    </script>
    
    <style scoped>
    .control {
       width: calc(100% - 20px);
       background: #ff0000;
       height: 10px;
      position: relative;
    }
    .slider_circle {
      position: absolute;
      width:20px;
      height: 20px;
      border-radius: 10px;
      border: 1px;
      background: #0000ff;
      margin-top: -15px;
    }
    
    .slider_circle_large {
      position: absolute;
      width:50px;
      height: 50px;
      border-radius: 25px;
      border: 1px;
      background: #00ffff;
      opacity: 0.8;
      top: -20px;
      left:-20px;
    }
    
    </style>

    说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

             对应的源码可以访问这里获取: https://github.com/liuhongdi/
             或: https://gitee.com/liuhongdi

    说明:作者:刘宏缔 邮箱: 371125307@qq.com

    二,测试效果

    三,查看vue框架的版本:

    liuhongdi@lhdpc:/data/vue/imgtouch$ npm list vue
    imgtouch@0.1.0 /data/vue/imgtouch
    ├─┬ @vue/cli-plugin-babel@5.0.4
    │ └─┬ @vue/babel-preset-app@5.0.4
    │   └── vue@3.2.36 deduped
    ├─┬ element-plus@2.2.2
    │ ├─┬ @element-plus/icons-vue@1.1.4
    │ │ └── vue@3.2.36 deduped
    │ ├─┬ @vueuse/core@8.6.0
    │ │ ├─┬ @vueuse/shared@8.6.0
    │ │ │ └── vue@3.2.36 deduped
    │ │ ├─┬ vue-demi@0.13.1
    │ │ │ └── vue@3.2.36 deduped
    │ │ └── vue@3.2.36 deduped
    │ └── vue@3.2.36 deduped
    └─┬ vue@3.2.36
      └─┬ @vue/server-renderer@3.2.36
        └── vue@3.2.36 deduped
  • 相关阅读:
    arr.forEach()与for...in的用法举例
    git
    hql查询
    JAVA Hibernate工作原理及为什么要用
    mysql中key 、primary key 、unique key 与index区别
    aop
    hibernate json数据死循环
    nginx 转帖
    Maven搭建web项目
    ajaxfileupload 附加参数
  • 原文地址:https://www.cnblogs.com/architectforest/p/16388708.html
Copyright © 2020-2023  润新知