vue3实现video控件的h5端进度条拖拽与跳转

代码:

<template>
    <div class="video-box">
<!--            poster="static/video/covershu.png"-->
        <video
            ref="homeVideo"
            id="video"
            class="video"
            src="https://www.w3school.com.cn/i/movie.ogg"
            :playsinline="true"
            :webkit-playsinline="true"
            @canplay="getVideoInfo"
            @timeupdate="getCurrentInfo"
            @ended="handleEnd"
            @click="dispControls"
            loop
            :x5-video-player-fullscreen="true"
            x5-video-orientation="portraint"
        >
            <p>你的浏览器不支持video标签.</p>
        </video>
        <div id="controls"  class="controls">
<!--            pause play -->
            <van-icon
                :name="iconName"
                class="play-btn"
                @click="playOrPause"
                color="white"
            />
            <div class="slider">
                <!-- 进度条容器 -->
                <div
                    id="control"
                    ref="control"
                    class="control"
                    @click="setProgress"
                    @touchmove="controlMove"
                    @touchend="controlEnd"
                >
                    <!-- 进度条本条 -->
                    <div
                        class="progress"
                        :style="{width: progressWidth + 'px' }"
                    />
                    <!-- 滑块 -->
                    <div
                        v-if="progressWidth - 10 > 0"
                        class="slider_circle"
                        :style="{left: (progressWidth - 10) + 'px' }"
                        @touchstart="sliderStart"
                    />
                </div>
            </div>
            <span>
                {{currentTime }} / {{ duration}}
            </span>
        </div>
    </div>
</template>

<script setup>
import {ref} from "vue"

//video的ref
const homeVideo = ref(null)
// 展厅或者播放
const iconName = ref('play')
//显示总时长
const duration = ref(0)
//显示播放到的当前时间
const currentTime = ref(0)

//滑动到位置的高度
const progressWidth = ref(0)
//移动的类型,用来标明是否在拖动进度条
const moveType = ref("")
//拖动开始时点击的位置
const moveOffsetX = ref(0)
//拖动开始时进度条的宽度度
const curWidth = ref(0)



//播放暂停
const playOrPause = () => {
    if (homeVideo.value.paused) {
        homeVideo.value.play()
        iconName.value = 'pause'
    } else {
        homeVideo.value.pause()
        iconName.value = 'play'
    }
}


//得到视频的时长等信息
const getVideoInfo = () => {
    duration.value = formatTime(parseInt(homeVideo.value.duration))
}

// 视频播放完毕
const handleEnd = () => {
    iconName.value = 'pause'
}
//得到视频当前播放到哪里的信息
const getCurrentInfo = () => {
    // 视频已经播放时长
    currentTime.value = formatTime(parseInt(homeVideo.value.currentTime))
    let ratio = homeVideo.value.currentTime / homeVideo.value.duration
    let allWidth = document.getElementById('control').getBoundingClientRect().width
    progressWidth.value = allWidth * ratio
}

// 格式化时间函数
const formatTime = (s) => {
    let t
    if (s > -1) {
        let hour = Math.floor(s / 3600)
        let min = Math.floor(s / 60) % 60
        let 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()
    progressWidth.value = e.clientX - left
    updadteCurrentTime(progressWidth.value, width)
}

//设置视频播放到指定的长度
const updadteCurrentTime = (progressWidth, width) => {
    let dest = (progressWidth / width) * homeVideo.value.duration
    homeVideo.value.currentTime = Math.floor(dest)
}


//当开始触摸开始在圆点按下时
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 = ""
}


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'
    }
}
</script>

<style lang="less">
@import "index.less";
</style>

index.less文件:

.video-box {
    width:100%;
    height: 100vh;
    background-color: #000;
    .video {
        width: 100vw;
        height: 422px;
        margin-top: 200px;
    }
    .controls {
        width: 100vw;
        z-index: 1;
        display: flex;
        align-items: center;
        .play-btn {
            width: 30px;
            height: 30px;
            padding: 20px;
        }
        .progress {
            height: 7px;
            border-radius: 3px;
            background-color: #e4c487;
        }
        .slider {
            flex: 1;
            .control {
                width: 100%;
                background-color: white;
                padding: 20px 0;
                position: relative;
                background-clip: content-box;
                z-index: 2;
            }
        }
        span {
            color: white;
            font-size: 24px;
            padding: 0 20px;
        }
        .slider_circle {
            position: absolute;
            left: 0;
            top: 13px;
            width: 20px;
            height: 20px;
            border-radius: 10px;
            border: 1px;
            background: #e4c487;
        }
    }
}




效果图: