需求
一個進度條組件控制多個視頻的播放、進度調(diào)整。視頻可點擊全屏觀看,唯一的進度條是某個指定視頻的視頻信息。
圖示
實現(xiàn)
html
//視頻
<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>
vue.js
全屏
handleFullScreen(item) {
this.isFullScreen = !this.isFullScreen //isFullScreen 定義為布爾值,控制樣式用的,給視頻容器高度設(shè)置為100vh,寬度100%實現(xiàn)全屏顯示
this.fullVideoType = item.type //控制樣式用的,不必要
},
點擊進度條跳轉(zhuǎn)
adjustProgress(e) {
e.preventDefault()
// 這里的this.controlRef = this.$refs.control,加載完視頻后定義即可
const { left, width } = this.controlRef.getBoundingClientRect()
// left: 進度條容器control到最左側(cè)的距離,width:容器的寬度
// e.clientX:鼠標點擊的位置到最左側(cè)的距離
const progressWidth = e.clientX - left
this.progressWidth = progressWidth + 'px'
this.updadteCurrentTime(progressWidth, width)
},
拖動滑塊
在菜鳥教程上有以下幾個參數(shù)的詳細解說,這張圖忘記哪里看的了,如有認領(lǐng)可評論我貼鏈接
handleSliderMouseDown(event) {
//如果不添加以下兩處的阻止默認事件,會出現(xiàn)以下情況: 鼠標點擊滑塊向前拉動,移出進度條范圍時,會自動選擇文字等元素,出現(xiàn)禁用圖標。松開鼠標,再次進入進度條,即使沒有按住滑塊,滑塊也會跟隨鼠標移動。這不是我們想要看到的效果。
event.preventDefault()
// 滑塊點擊坐標
const offsetX = event.offsetX
document.onmousemove = (e) => {
e.preventDefault()
// 滑動距離可視區(qū)域左側(cè)的距離
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)
}
//抬起鼠標,結(jié)束移動事件
document.onmouseup = () => {
document.onmousemove = null
document.onmouseup = null
}
},
倍速
// 倍速
handleChangeSpeed(item) {
this.playSpeed = item
},
播放暫停
play() {
//是否暫停
this.paused = !this.paused
// 若此刻狀態(tài)是重新播放,那么點擊播放時,進度條需從頭開始前進
// 進度條控制的是中間視頻,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)
// 放完、暫停這兩種情況,遍歷所有視頻,使他們的狀態(tài)一致,并清除定時器
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
}
跳轉(zhuǎn)、拖動后更新進度條長度是通過更新視頻的currentTime
// 更新當前時間、幀號
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
})
},
總結(jié):公司內(nèi)部使用需要寫這樣一個組件。雖然比較不通用,但是比較靈活。html結(jié)構(gòu)為了看的直觀點,省略了相關(guān)樣式。
有感興趣的可以一起討論。文章來源:http://www.zghlxwxcb.cn/news/detail-517445.html
原創(chuàng)不易,轉(zhuǎn)載請貼出處文章來源地址http://www.zghlxwxcb.cn/news/detail-517445.html
到了這里,關(guān)于vue自定義h5video視頻播放器進度條組件,可拖拽、跳轉(zhuǎn)、倍速、全屏的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!