说在前面
在短视频兴起的时代,很多的视频软件都有视频加速的功能,只需轻轻长按屏幕,视频便会根据预设的速度模式进行倍速播放,这是很常用而且很实用的一个功能,今天就让我们来简单实现一个组件,支持长按屏幕加速,且可以滑动选择加速倍率。
效果展示
pc端
移动端
体验地址
组件实现
1、组件属性(props)
width
视频播放器的宽度,可传入如 "300px"
、"50%"
等合法的 CSS 宽度值。默认值为"300px"
。
height
视频播放器的高度,接受合法的 CSS 高度值。默认为"200px"
。
videoUrl
视频的源地址,需为有效的视频文件 URL,本地视频或线上链接都行。
javascript
代码解读
复制代码
videoUrl: require("../../assets/video/密码箱.mp4"), videoUrl: "http://jyeontu.xyz/video/202112250058.mp4",
loop
是否循环播放视频,默认为false
。
timeIntervalLimit
长按事件的时间间隔限制(单位:毫秒),用于判断长按操作的触发条件,默认为1500
,即长按屏幕1.5
就会触发长按加速事件。
speedChooseList
可选的播放速度列表,数组元素为数字,表示倍速,默认为 [2, 3, 4]
。
2、获取video位置尺寸
获取视频元素和组件容器的位置和尺寸信息,存储在 videoContentInfo
中,用于后续的长按位置计算和速度调节。
javascript
代码解读
复制代码
initVideoContentInfo() { const JVideoSpeedBox = this.$refs[this.uid + "-JVideoSpeed"]; const videoContent = this.$refs[this.uid + "-video"]; const videoContentInfo = { offSetTop: videoContent.offsetTop || JVideoSpeedBox.offsetTop, offsetLeft: videoContent.offsetLeft || JVideoSpeedBox.offsetLeft, height: videoContent.offsetHeight || JVideoSpeedBox.offsetHeight, width: videoContent.offsetWidth || JVideoSpeedBox.offsetWidth, }; this.videoContentInfo = videoContentInfo; },
3、video点击事件
处理视频的点击事件,实际上调用 videoMouseUp
方法,用于统一处理视频播放状态的切换逻辑,避免在点击和其他操作(如长按后松开)时出现不一致的播放状态。
javascript
代码解读
复制代码
videoClick(e) { this.videoMouseUp(e); },
4、鼠标按下事件
处理鼠标按下事件,记录按下时间 downTime
,并在 timeIntervalLimit
后判断是否为长按操作,如果视频未暂停,则执行 videoLongPress
方法展示速度选择面板并进行速度调节。
javascript
代码解读
复制代码
videoMouseDown(e) { this.downTime = new Date().getTime(); setTimeout(() => { const videoContent = this.$refs[this.uid + "-video"]; if (videoContent.paused) { this.downTime = null; return; } if (!this.downTime) return; this.videoLongPress(e); }, this.timeIntervalLimit); },
5、长按结束事件
在长按停止时,将播放速度恢复为正常速度(1 倍速),并在视频暂停时恢复播放,确保视频播放状态的正确切换和速度的正常恢复。
javascript
代码解读
复制代码
videoLongPressStop(e) { this.speedRate = 1; const target = e.target; if (target.className !== "j-video-speed-content") return; const videoContent = this.$refs[this.uid + "-video"]; setTimeout(() => { if (videoContent.paused) { videoContent.play(); } }, 50); },
6、选中速度设置
更新速度选择面板中当前选中速度选项的样式,通过添加或移除特定的类名(j-video-speed-rates-rate-acitvity
)来实现视觉上的选中反馈,增强用户交互体验。如果获取元素失败,会尝试重新获取和更新样式,以应对可能的加载延迟或其他异常情况。
- 参数:
rate
:要设置为选中状态的播放速度值,用于确定对应的速度选项元素并更新其样式。times
(可选):重试次数,默认为 1,用于递归调用时控制重试逻辑,避免无限循环。
javascript
代码解读
复制代码
videoSpeedRateTextChange(rate, times = 1) { try { const rateContents = document.getElementsByClassName( "j-video-speed-rates-rate-acitvity" ); for (const item of rateContents) { item.classList.remove("j-video-speed-rates-rate-acitvity"); } if (!this.speedChooseList.includes(rate)) return; const rateContent = this.$refs[this.uid + "speedRate" + rate][0]; rateContent.classList.add("j-video-speed-rates-rate-acitvity"); } catch (err) { if (!times) return; setTimeout(() => { this.videoSpeedRateTextChange(rate, times - 1); }, 100); } },
7、视频播放速度修改
直接设置视频的播放速度,通过修改视频元素的 playbackRate
属性来实现,并更新 speedRate
数据,以便组件内部记录和后续操作使用。
- 参数:
rate
:要设置的播放速度值,需为数字类型,如 2、3 等,表示倍速。
javascript
代码解读
复制代码
videoSpeedRateChange(rate) { const videoContent = this.$refs[this.uid + "-video"]; videoContent.playbackRate = rate; this.speedRate = rate; },
8、视频长按事件
在长按视频时触发,展示速度选择面板(showRagePanel
设为 true
),计算长按位置对应的播放速度值,并调用 videoSpeedRateChange
和 videoSpeedRateTextChange
方法来设置和显示选中的速度选项,实现快速的播放速度调节。
javascript
代码解读
复制代码
videoLongPress(e) { this.showRagePanel = true; const rate = this.calcSpeedRate(e); if (!rate) return; this.videoSpeedRateChange(rate); this.videoSpeedRateTextChange(rate); },
9、计算加速倍率
根据长按位置(layerY
)和速度选择列表,计算出对应的播放速度值。如果长按位置超出视频区域或不符合计算条件,则返回 null
。通过将长按位置与每个速度选项对应的区域高度进行比较,确定用户选择的速度值,为速度调节提供准确的数据支持。
javascript
代码解读
复制代码
calcSpeedRate(e) { const videoContentInfo = this.videoContentInfo; let layerY = e.layerY; if (!e.layerY && e.touches) { layerY = e.touches[0].pageY - videoContentInfo.offSetTop; } if (layerY < 0) return; const preSpeedRateHeight = videoContentInfo.height / this.speedChooseList.length; const speedRate = this.speedChooseList[Math.floor(layerY / preSpeedRateHeight)]; return speedRate; },
10、鼠标(触屏)移动事件
处理视频的移动事件(在长按过程中),根据时间间隔判断是否满足长按条件,如果满足则执行 videoLongPress
方法继续速度调节操作,确保在长按拖动过程中能实时响应速度变化。同时,通过 e.preventDefault()
阻止默认的滚动行为,避免页面滚动干扰视频操作。
javascript
代码解读
复制代码
videoMove(e) { if (!this.downTime) return; const videoContent = this.$refs[this.uid + "-video"]; if (videoContent.paused) { this.downTime = null; return; } e.preventDefault(); const nowTime = new Date().getTime(); const timeDif = nowTime - this.downTime; if (timeDif >= this.timeIntervalLimit) { this.videoLongPress(e); } },
11、切换视频的播放状态
长按结束后恢复视频原始播放状态,在一定延迟(50 毫秒)后切换视频的播放状态,即如果视频当前暂停,则恢复播放;如果正在播放,则暂停播放。通过 setTimeout
实现延迟操作,确保播放状态的切换在合适的时机进行,避免与其他操作冲突。
javascript
代码解读
复制代码
changeVideoPlayStaus() { const videoContent = this.$refs[this.uid + "-video"]; setTimeout(() => { if (videoContent.paused) { videoContent.play(); } else { videoContent.pause(); } }, 50); },
12、鼠标抬起(触屏结束)事件
处理鼠标松开事件,将播放速度恢复为正常速度(1 倍速),根据按下和松开的时间间隔判断是否为长按操作,如果是长按操作,则执行 videoLongPressStop
方法进行后续处理;否则,如果是触摸事件且时间间隔较短,则调用 changeVideoPlayStaus
方法切换视频播放状态。同时,隐藏速度选择面板(showRagePanel
设为 false
),完成一次完整的视频操作交互流程。
javascript
代码解读
复制代码
videoMouseUp(e) { this.videoSpeedRateChange(1); if (!this.downTime) return; const upTime = new Date().getTime(); const timeDif = upTime - this.downTime; this.downTime = null; this.showRagePanel = false; if (timeDif >= this.timeIntervalLimit) { this.videoLongPressStop(e); return; } else { if (e.touches) this.changeVideoPlayStaus(); } },
组件使用
html
代码解读
复制代码
<template> <div class="content"> <div class="video-list"> <JVideoSpeed class="video" :videoUrl="videoUrl" videoWidth: "768px", videoHeight: "412px", :speedChooseList="speedChooseList" > </JVideoSpeed> </div> </div> </template> <script> export default { data() { return { videoUrl: require("../../assets/video/202112250058.mp4"), speedChooseList: [2, 3, 4, 5], videoWidth: "768px", videoHeight: "412px", } }, created() { this.initVideoBox(); }, methods:{ initVideoBox() { const videoWidth = parseInt(this.videoWidth); const videoHeight = parseInt(this.videoHeight); const rate = videoWidth / videoHeight; const width = window.innerWidth; const height = window.innerHeight; if (width < height) { this.videoWidth = width * 0.95 + "px"; this.videoHeight = (width * 0.95) / rate + "px"; } }, } } </script>
组件库
组件文档
目前该组件也已经收录到我的组件库,组件文档地址如下: jyeontu.xyz/jvuewheel/#…
组件内容
组件库中还有许多好玩有趣的组件,如:
- 评论组件
- 词云组件
- 瀑布流照片容器
- 视频动态封面
- 3D轮播图
- web桌宠
- 贡献度面板
- 拖拽上传
- 自动补全输入框
- 图片滑块验证
等等……
组件库源码
组件库已开源到gitee,有兴趣的也可以到这里看看:gitee.com/zheng_yongt…
🌟觉得有帮助的可以点个star~
🖊有什么问题或错误可以指出,欢迎pr~
📬有什么想要实现的组件或想法可以联系我~
公众号
关注公众号『前端也能这么有趣
』,获取更多有趣内容。
发送『组件库
』获取源码
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。
原文链接:https://juejin.cn/post/7448513468662743051