说在前面
在短视频兴起的时代,很多的视频软件都有视频加速的功能,只需轻轻长按屏幕,视频便会根据预设的速度模式进行倍速播放,这是很常用而且很实用的一个功能,今天就让我们来简单实现一个组件,支持长按屏幕加速,且可以滑动选择加速倍率。
效果展示
pc端
移动端
体验地址
组件实现
1、组件属性(props)
width
视频播放器的宽度,可传入如 "300px"、"50%" 等合法的 CSS 宽度值。默认值为"300px"。
height
视频播放器的高度,接受合法的 CSS 高度值。默认为"200px"。
videoUrl
视频的源地址,需为有效的视频文件 URL,本地视频或线上链接都行。
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 中,用于后续的长按位置计算和速度调节。
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 方法,用于统一处理视频播放状态的切换逻辑,避免在点击和其他操作(如长按后松开)时出现不一致的播放状态。
videoClick(e) {
this.videoMouseUp(e);
},
4、鼠标按下事件
处理鼠标按下事件,记录按下时间 downTime,并在 timeIntervalLimit 后判断是否为长按操作,如果视频未暂停,则执行 videoLongPress 方法展示速度选择面板并进行速度调节。
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 倍速),并在视频暂停时恢复播放,确保视频播放状态的正确切换和速度的正常恢复。
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,用于递归调用时控制重试逻辑,避免无限循环。
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 等,表示倍速。
videoSpeedRateChange(rate) {
const videoContent = this.$refs[this.uid + "-video"];
videoContent.playbackRate = rate;
this.speedRate = rate;
},
8、视频长按事件
在长按视频时触发,展示速度选择面板(showRagePanel 设为 true),计算长按位置对应的播放速度值,并调用 videoSpeedRateChange 和 videoSpeedRateTextChange 方法来设置和显示选中的速度选项,实现快速的播放速度调节。
videoLongPress(e) {
this.showRagePanel = true;
const rate = this.calcSpeedRate(e);
if (!rate) return;
this.videoSpeedRateChange(rate);
this.videoSpeedRateTextChange(rate);
},
9、计算加速倍率
根据长按位置(layerY)和速度选择列表,计算出对应的播放速度值。如果长按位置超出视频区域或不符合计算条件,则返回 null。通过将长按位置与每个速度选项对应的区域高度进行比较,确定用户选择的速度值,为速度调节提供准确的数据支持。
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() 阻止默认的滚动行为,避免页面滚动干扰视频操作。
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 实现延迟操作,确保播放状态的切换在合适的时机进行,避免与其他操作冲突。
changeVideoPlayStaus() {
const videoContent = this.$refs[this.uid + "-video"];
setTimeout(() => {
if (videoContent.paused) {
videoContent.play();
} else {
videoContent.pause();
}
}, 50);
},
12、鼠标抬起(触屏结束)事件
处理鼠标松开事件,将播放速度恢复为正常速度(1 倍速),根据按下和松开的时间间隔判断是否为长按操作,如果是长按操作,则执行 videoLongPressStop 方法进行后续处理;否则,如果是触摸事件且时间间隔较短,则调用 changeVideoPlayStaus 方法切换视频播放状态。同时,隐藏速度选择面板(showRagePanel 设为 false),完成一次完整的视频操作交互流程。
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();
}
},
组件使用
<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,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。