揭秘滑动方向检测背后的原理与实际应用技巧
先看效果,再看代码
最近项目里有个需求,要根据用户滑动的方向来做不同的操作,比如上滑显示菜单,下滑隐藏菜单。这个东西听起来简单,但真做起来各种坑等着你。今天就来分享下我是怎么搞定它的。
核心代码就这几行
首先,我们要监听touchstart和touchend事件来获取用户的触摸起点和终点。然后通过计算起点和终点的坐标差来判断滑动的方向。
let startX, startY, endX, endY;
document.addEventListener('touchstart', function(e) {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
});
document.addEventListener('touchend', function(e) {
endX = e.changedTouches[0].clientX;
endY = e.changedTouches[0].clientY;
handleSwipe();
});
handleSwipe函数解析
接下来,我们要定义handleSwipe函数来处理滑动事件。这里的关键是要计算X轴和Y轴的变化量,然后根据变化量的大小和方向来决定执行什么操作。
function handleSwipe() {
let xDiff = startX - endX;
let yDiff = startY - endY;
if (Math.abs(xDiff) > Math.abs(yDiff)) {
if (xDiff > 0) {
console.log('左滑');
} else {
console.log('右滑');
}
} else {
if (yDiff > 0) {
console.log('上滑');
} else {
console.log('下滑');
}
}
}
谁更灵活?谁更省事?
上面的代码虽然简单直接,但在实际项目中可能不够灵活。比如,你可能需要考虑滑动的距离阈值,或者在某些情况下忽略滑动事件。为了增加灵活性,我们可以稍微改造一下handleSwipe函数。
function handleSwipe(threshold = 50) {
let xDiff = startX - endX;
let yDiff = startY - endY;
if (Math.abs(xDiff) > threshold && Math.abs(xDiff) > Math.abs(yDiff)) {
if (xDiff > 0) {
console.log('左滑');
} else {
console.log('右滑');
}
} else if (Math.abs(yDiff) > threshold) {
if (yDiff > 0) {
console.log('上滑');
} else {
console.log('下滑');
}
}
}
这个场景最好用
假设我们有一个菜单栏,用户上滑时显示菜单,下滑时隐藏菜单。结合刚才的代码,我们很容易实现这个功能。
<div id="menu" style="position: fixed; bottom: 0; left: 0; width: 100%; height: 100px; background-color: #333; color: white; display: none;">
菜单项1 | 菜单项2 | 菜单项3
</div>
let menu = document.getElementById('menu');
document.addEventListener('touchstart', function(e) {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
});
document.addEventListener('touchend', function(e) {
endX = e.changedTouches[0].clientX;
endY = e.changedTouches[0].clientY;
handleSwipe();
});
function handleSwipe(threshold = 50) {
let xDiff = startX - endX;
let yDiff = startY - endY;
if (Math.abs(yDiff) > threshold) {
if (yDiff > 0) {
// 上滑
menu.style.display = 'block';
} else {
// 下滑
menu.style.display = 'none';
}
}
}
踩坑提醒:这三点一定注意
在做这个功能的时候,我踩了几个坑,现在想起来还是忍不住吐槽一下。
- touchmove滚动失效:一开始我直接用了
touchmove事件,但发现在某些浏览器上滚动会失效。后来发现是因为touchmove事件默认是阻止滚动的,需要手动取消默认行为。 - 多指滑动问题:当用户使用多根手指滑动时,
touches数组会有多个元素,这时候如果只取第一个元素会导致滑动方向判断错误。 - 事件监听的时机:确保在DOM加载完成后才添加事件监听器,否则可能会导致事件无法触发。
解决这些问题的方法很简单,比如给touchmove事件加上event.preventDefault(),或者在处理滑动事件前先判断touches.length是否为1。
高级技巧:防抖处理
如果你的应用中有很多滑动相关的操作,频繁的触发事件可能会导致性能问题。这时可以使用防抖技术来减少事件触发的频率。
let debounceTimer;
function handleSwipe(threshold = 50) {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
let xDiff = startX - endX;
let yDiff = startY - endY;
if (Math.abs(yDiff) > threshold) {
if (yDiff > 0) {
// 上滑
menu.style.display = 'block';
} else {
// 下滑
menu.style.display = 'none';
}
}
}, 200); // 200毫秒的防抖时间
}
以上是我踩坑后的总结,希望对你有帮助
这个技术的拓展用法还有很多,后续会继续分享这类博客。如果你有更好的实现方式,欢迎评论区交流。
本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。

暂无评论