赞
踩
一个进度条组件控制多个视频的播放、进度调整。视频可点击全屏观看,唯一的进度条是某个指定视频的视频信息。
//视频 <div v-for="(item, index) in urls" :key="index" > <video :ref="item.type" preload="auto" :src="item.url" /> <div> // svg-icon是icon图标组件 <svg-icon v-if="!isFullScreen" :style="{ fill: '#dbdbdb', 'font-size': 20 + 'px' }" icon-class="quanping_o" @click="handleFullScreen(item)" /> <svg-icon v-else :style="{ fill: '#dbdbdb', 'font-size': 20 + 'px' }" icon-class="quxiaoquanping_o" @click="handleFullScreen(item)" /> </div> </div> //进度条 <div v-show="fileUrl" class="progress-wrap"> <div class="operate"> <div class="speed"> //倍速列表 <el-menu class="list" mode="horizontal"> <el-menu-item v-for="(speed, i) in speedList" :key="i" class="list-item" @click="handleChangeSpeed(speed)">{{ speed }}</el-menu-item> </el-menu> //显示倍速 {{ playSpeed }}x </div> <div> <div class="play-wrap" @click="play"> <svg-icon v-if="!paused" icon-class="zanting" :style="{ 'font-size': 14 + 'px' }" /> <svg-icon v-else-if="paused" icon-class="bofang" :style="{ 'font-size': 14 + 'px' }" /> </div> // 显示已播放时长和总时长 <div class="timer">{{ currentTime }} / {{ totalTime }}</div> </div> </div> //进度条容器 <div ref="control" class="control" @click="adjustProgress($event)"> // 进度条本条 <div class="progress" :style="{ width: progressWidth }"> //滑块 <div class="slider_circle" @mousedown="handleSliderMouseDown" /> <div class="slider_circle_large" /> </div> </div> </div>
handleFullScreen(item) {
this.isFullScreen = !this.isFullScreen //isFullScreen 定义为布尔值,控制样式用的,给视频容器高度设置为100vh,宽度100%实现全屏显示
this.fullVideoType = item.type //控制样式用的,不必要
},
adjustProgress(e) {
e.preventDefault()
// 这里的this.controlRef = this.$refs.control,加载完视频后定义即可
const { left, width } = this.controlRef.getBoundingClientRect()
// left: 进度条容器control到最左侧的距离,width:容器的宽度
// e.clientX:鼠标点击的位置到最左侧的距离
const progressWidth = e.clientX - left
this.progressWidth = progressWidth + 'px'
this.updadteCurrentTime(progressWidth, width)
},
在菜鸟教程上有以下几个参数的详细解说,这张图忘记哪里看的了,如有认领可评论我贴链接
handleSliderMouseDown(event) { //如果不添加以下两处的阻止默认事件,会出现以下情况: 鼠标点击滑块向前拉动,移出进度条范围时,会自动选择文字等元素,出现禁用图标。松开鼠标,再次进入进度条,即使没有按住滑块,滑块也会跟随鼠标移动。这不是我们想要看到的效果。 event.preventDefault() // 滑块点击坐标 const offsetX = event.offsetX document.onmousemove = (e) => { e.preventDefault() // 滑动距离可视区域左侧的距离 const X = e.clientX // 减去滑块偏移量 const cl = X - offsetX const { left, width } = this.controlRef.getBoundingClientRect() // 除去滑块按钮长度的进度条长度 const ml = cl - left let progressWidth if (ml <= 0) { //进度条长度最小和最大值的界定 progressWidth = 0 } else if (ml >= width) { progressWidth = width } else { progressWidth = ml } this.progressWidth = progressWidth + 'px' // 更新当前时间 this.updadteCurrentTime(progressWidth, width) } //抬起鼠标,结束移动事件 document.onmouseup = () => { document.onmousemove = null document.onmouseup = null } },
// 倍速
handleChangeSpeed(item) {
this.playSpeed = item
},
play() { //是否暂停 this.paused = !this.paused // 若此刻状态是重新播放,那么点击播放时,进度条需从头开始前进 // 进度条控制的是中间视频,this.middleRef if (this.middleRef.duration === this.middleRef.currentTime) { this.middleRef.currentTime = 0 this.currentTime = this.formatSeconds(this.middleRef.currentTime) this.progressWidth = 0 + 'px !important' } if (!this.paused) { // 定时器实时刷新 this.timer = setInterval(this.updateVideoProgress, 50) this.updateVideoProgress() } this.videoRefArr.forEach((v) => { v.currentTime = this.middleRef.currentTime if (this.paused) { v.pause() } else { v.play() // 按倍速播放 v.playbackRate = this.playSpeed } }) }, clearTimer() { if (this.timer) { clearInterval(this.timer) this.timer = null } }, // 更新播放时进度条长度 updateVideoProgress() { //按照已播放时间和总时长的比例更新进度条长度 this.progressWidth = (this.middleRef.currentTime / this.middleRef.duration) * 100 + '%' this.currentTime = this.formatSeconds(this.middleRef.currentTime) this.totalTime = this.formatSeconds(this.middleRef.duration) // 放完、暂停这两种情况,遍历所有视频,使他们的状态一致,并清除定时器 if (this.middleRef.currentTime === this.middleRef.duration || this.paused) { this.videoRefArr.forEach((v) => { v.pause() }) this.paused = true this.clearTimer() } }, // 格式化时间 formatSeconds(value) { const result = parseInt(value) const h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600) const m = Math.floor((result / 60) % 60) < 10 ? '0' + Math.floor((result / 60) % 60) : Math.floor((result / 60) % 60) const s = Math.floor(result % 60) < 10 ? '0' + Math.floor(result % 60) : Math.floor(result % 60) //把视频时长格式化到毫秒 let ms const msValue = value.toFixed(3).toString().split('.')[1] if (Math.floor(msValue % 1000) < 10) { ms = '00' + Math.floor(msValue % 1000) } else if (Math.floor(msValue % 1000) > 10 && Math.floor(msValue % 1000) < 100) { ms = '0' + Math.floor(msValue % 1000) } else if (Math.floor(msValue % 1000) < 1000) { ms = Math.floor(msValue % 1000) } let res = '' res += `${h}:` res += `${m}:` res += `${s}.` res += `${ms}` return res }
// 更新当前时间、帧号
updadteCurrentTime(progressWidth, width) {
this.currentTime = this.formatSeconds((progressWidth / width) * this.middleRef.duration)
this.totalTime = this.formatSeconds(this.middleRef.duration)
this.videoRefArr.forEach((v) => {
v.currentTime = (progressWidth / width) * this.middleRef.duration
})
},
总结:公司内部使用需要写这样一个组件。虽然比较不通用,但是比较灵活。html结构为了看的直观点,省略了相关样式。
有感兴趣的可以一起讨论。
原创不易,转载请贴出处
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。