揭秘滑动方向检测背后的原理与实际应用技巧

旗施🍀 交互 阅读 2,427
赞 24 收藏
二维码
手机扫码查看
反馈

先看效果,再看代码

最近项目里有个需求,要根据用户滑动的方向来做不同的操作,比如上滑显示菜单,下滑隐藏菜单。这个东西听起来简单,但真做起来各种坑等着你。今天就来分享下我是怎么搞定它的。

揭秘滑动方向检测背后的原理与实际应用技巧

核心代码就这几行

首先,我们要监听touchstarttouchend事件来获取用户的触摸起点和终点。然后通过计算起点和终点的坐标差来判断滑动的方向。

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立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论