vue.js3: 自定义video可拖动的进度条(vue@3.2.36)
一,js代码:
<template> <div> <div style="position:relative;"> <video ref="homeVideo" style="position: absolute; width: 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;width:100%;height:50px;background: rgb(255, 255, 0); position: absolute; z-index: 99;"> <button @click="playOrPause">playOrPausebutton> <button @click="openOrSlient">开关音量button> <button @click="fullScreen">全屏button> <div> 总时长:{{duration}} 当前位置:{{currentTime}} div> <div style="width: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',width: 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("allwidth:"+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