其他分享
首页 > 其他分享> > vue.js3: 自定义video垂直可拖动的进度条(vue@3.2.36)

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

作者:互联网

一,js代码

<template>
  <div style="background: rgb(0, 0, 0);width:100%;height:100vh;">
    <div style="position:relative;">

      <video ref="homeVideo"
             style="position: absolute; width: 100vw; height: 100vh; left:0;visibility:visible;"
             poster="static/video/covershu.png" id="video"
             class="video" src="static/video/guotoushu.mp4" type="video/mp4"
             playsinline="true" webkit-playsinline="true"
             @canplay="getVideoInfo"
             @timeupdate="getCurrentInfo"
             @click="dispControls"
             x5-video-player-fullscreen="true" x5-video-orientation="portraint"
             loop="-1">
        <p>你的浏览器不支持video标签.</p>
      </video>

      <div id="controls" style="background-image: linear-gradient(to right,black,transparent);width:40px;
height:100vh; position: absolute; z-index: 99;"> <img ref="playButton" @click="playOrPause" src="static/svg/video-play.svg" style="transform:rotate(90deg);width:30px;height:30px;margin-top:10px;"/> <!-- <div> 总时长:{{duration}} 当前位置:{{currentTime}} </div> --> <div style="margin-top:15px;width: 5px; height: calc(100vh - 165px); margin-left: 17px;"> <!-- 进度条容器 --> <div id="control" ref="control" class="control" @click="setProgress" @touchmove="controlMove" @touchend="controlEnd"> <!-- 进度条本条 --> <div class="progress" :style="{background:'#ffffff', width:'5px',height: progressHeight+'px' }"> </div> <!-- 滑块 --> <div class="slider_circle" :style="{top: (progressHeight-10)+'px' }" @touchstart="sliderStart" /> <div class="slider_circle_large" :style="{top: (progressHeight - 25)+'px' }" @touchstart="sliderStart" /> </div> </div> <img ref="muteButton" @click="openOrSlient" src="static/svg/microphone.svg" style="transform:rotate(90deg);width:30px;height:30px;margin-top:20px;"/> <img @click="fullScreen" src="static/svg/full-screen.svg" style="transform:rotate(90deg);width:30px;height:30px;margin-top:10px;"/> </div> </div> </div> </template> <script> import { ref } from "vue"; export default { name: "Video3Img", 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(); playButton.value.src="static/svg/video-pause.svg"; } else { homeVideo.value.pause(); playButton.value.src="static/svg/video-play.svg"; } } //开关音量 const openOrSlient = () => { console.log("muted1:"+homeVideo.value.muted); if (homeVideo.value.muted == true) { homeVideo.value.muted = false; muteButton.value.src="static/svg/microphone.svg"; } else { homeVideo.value.muted = true; muteButton.value.src="static/svg/mute.svg"; } } //全屏 const fullScreen = () => { homeVideo.value.requestFullscreen(); } //显示总时长 const duration = ref(0); //得到视频的时长等信息 const getVideoInfo = () => { duration.value = formatTime(parseInt(homeVideo.value.duration)); } //显示播放到的当前时间 const currentTime = ref(0); //滑动到位置的高度 const progressHeight = ref(0); //得到视频当前播放到哪里的信息 const getCurrentInfo = () => { // 视频已经播放时长 currentTime.value = formatTime(parseInt(homeVideo.value.currentTime)); //计算得到宽度: let ratio = homeVideo.value.currentTime / homeVideo.value.duration; //console.log("ratio:"+ratio); let allHeight = document.getElementById('control').getBoundingClientRect().height; //console.log("allwidth:"+allWidth); progressHeight.value = allHeight * 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 {top, height } = document.getElementById('control').getBoundingClientRect() // left: 进度条容器control到最左侧的距离 //15: 按钮宽度的一半 const proHeight = e.clientY - top progressHeight.value = proHeight; updadteCurrentTime(progressHeight.value, height); } //设置视频播放到指定的长度 const updadteCurrentTime = (progressHeight, height) => { let dest = (progressHeight / height) * homeVideo.value.duration; //console.log("dest:"+dest); homeVideo.value.currentTime = Math.floor(dest); } //移动的类型,用来标明是否在拖动进度条 const moveType = ref(""); //拖动开始时点击的位置 const moveOffsetY = ref(0); //拖动开始时进度条的宽度 const curHeight = ref(0); //当开始触摸开始在圆点按下时 const sliderStart = (e) => { e.preventDefault(); moveOffsetY.value = e.touches[0].clientY; moveType.value = "slider"; curHeight.value = progressHeight.value; } //当触摸在controls上移动时 const controlMove = (e) => { if (moveType.value !== 'slider') { return false; } e.preventDefault() // 滑动距离可视区域左侧的距离 const Y = e.touches[0].clientY //得到本次拖动已经过的距离 const cl = Y - moveOffsetY.value; //容器的宽度 const {height } = document.getElementById('control').getBoundingClientRect() //得到已拖动到的宽度 const ml = curHeight.value + cl let proHeight if (ml <= 0) { //进度条长度最小和最大值的界定 proHeight = 0 } else if (ml >= height) { proHeight = height } else { proHeight = ml } progressHeight.value = proHeight; // 更新当前时间 updadteCurrentTime(progressHeight.value, height); } //滑动结束 const controlEnd = () => { moveType.value = ""; } const playButton = ref(null); const muteButton = ref(null); const dispControls = () => { let isDisp = document.getElementById('controls').style.visibility; if (isDisp == 'hidden') { document.getElementById('controls').style.visibility = 'visible'; } else { document.getElementById('controls').style.visibility = 'hidden'; } } return { homeVideo, dispControls, playOrPause, playButton, muteButton, openOrSlient, fullScreen, getVideoInfo, duration, getCurrentInfo, currentTime, progressHeight, setProgress, //拖动 sliderStart, controlMove, controlEnd, } } } </script> <style scoped> .control { width: 5px; background: rgb(62,62,62); height: 100%; position: relative; } .slider_circle { position: absolute; width:20px; height: 20px; border-radius: 10px; border: 1px; background: #ffffff; /*margin-top: -15px;*/ left:-7px; opacity: 0.8; } .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

标签:vue,const,自定义,homeVideo,进度条,value,height,ref
来源: https://www.cnblogs.com/architectforest/p/16389504.html