检测用户的意图是点击还是在触觉设备上向上/向下滚动页面

Posted

技术标签:

【中文标题】检测用户的意图是点击还是在触觉设备上向上/向下滚动页面【英文标题】:Detect whether the intent of a user is to tap or to scroll up/down the page on tactile device 【发布时间】:2013-09-17 01:01:03 【问题描述】:

如果用户在弹出框外点击 (touchstart),我想隐藏弹出框。

但如果用户的意图是滚动/滑动 (touchmove),我不想隐藏弹出窗口。

代码如何检测和响应这两个操作(使用或不使用 jQuery)?

【问题讨论】:

尝试检测长按滑动和短按触摸 你能举个例子吗? 【参考方案1】:

以下是一个基本示例,说明如何执行此操作: http://jsfiddle.net/4CrES/2/

其背后的逻辑涉及检测初始触摸时间并将其保存到 var

touchTime = new Date();

在 touchend 处理程序中,从当前时间中减去这个时间以获得差值:

var diff = new Date() - touchTime;

使用 if 语句来决定触摸持续时间是短到足以将其视为轻击,还是足够长以将其视为拖动。

if (diff < 100)
    //It's a tap

else 
    //Not a quick tap

您可以通过在处理程序中对初始触摸 y 位置与最终触摸 y 位置进行类似的差异来编写更健壮的实现。另一种选择是比较滚动区域的scrollTop,看是否已经滚动。

【讨论】:

更新了小提琴 jsfiddle.net/4CrES/3 使其在浏览器上也能正常工作。所以mousedown(触摸设备中的touchstart)和mouseup(触摸设备中的touchend)被添加为事件,以便在浏览器中观察到相同的效果。【参考方案2】:

由于点击事件不会在移动 Safari 上冒泡 DOM,而触摸事件和自定义事件会冒泡,因此我最近编写了一些代码来检测快速点击。

这是一个快速点击

触摸事件开始和结束时屏幕上没有任何移动 没有滚动发生 这一切都发生在不到 200 毫秒的时间内。

如果触摸被确定为“quickTap”,TouchManager 会导致 DOM 中被触摸的元素发出自定义的“quickTap”事件,然后将 DOM 冒泡到碰巧正在监听它的任何其他元素。这段代码定义并创建了触摸管理器,它会立即准备就绪

缺点:

使用 jQuery 设计时只考虑一根手指。 还从modernizr 借用了一些代码。 (如果您已经包含 Modernizr,则可以省略该部分。)

也许这是矫枉过正,但它是我正在处理的更大代码库的一部分。

/** 
 * Click events do not bubble up the DOM on mobile Safari unless the click happens on a link or form input, but other events do bubble up.
 * The quick-tap detects the touch-screen equivalent of a click and triggers a custom event on the target of the tap which will bubble up the DOM.
 * A touch is considered a click if there is a touch and release without any movement along the screen or any scrolling.
 */

var qt = (function ($) 
    /**
     * Modernizr 3.0.0pre (Custom Build) | MIT 
     * Modernizr's touchevent test
     */
    var touchSupport = (function() 
            var bool,
                prefixes = ' -webkit- -moz- -o- -ms- '.split(' ')
            if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) 
                bool = true;
             else 
                var query = ['@media (',prefixes.join('touch-enabled),('),'heartz',')','#modernizrtop:9px;position:absolute'].join('');
                testStyles(query, function( node ) 
                    bool = node.offsetTop === 9;
                );
            
            return bool;
        ()),
        MobileTapEvent = 'tapEvent';

    if(touchSupport) 
        /* Create a new qt (constructor)*/
        var startTime = null,
            startTouch = null,
            isActive = false,
            scrolled = false;

        /* Constructor */
        function qt() 
            var _qt = this,
                context = $(document);
            context.on("touchstart", function (evt) 
                startTime = evt.timeStamp;
                startTouch = evt.originalEvent.touches.item(0);
                isActive = true;
                scrolled = false;
            )
            context.on("touchend", function (evt) 
                window.ct = evt.originalEvent['changedTouches'];
                // Get the distance between the initial touch and the point where the touch stopped.
                var duration = evt.timeStamp - startTime,
                    movement = _qt.getMovement(startTouch, evt.originalEvent['changedTouches'].item(0)), 
                    isTap = !scrolled && movement < 5 && duration < 200;
                if (isTap) 
                    $(evt.target).trigger('quickTap', evt);
                
            )
            context.on('scroll mousemove touchmove', function (evt) 
                if ((evt.type === "scroll" || evt.type === 'mousemove' || evt.type === 'touchmove') && isActive && !scrolled) 
                    scrolled = true;
                
            );
        

        /* Calculate the movement during the touch event(s)*/
        qt.prototype.getMovement = function (s, e) 
            if(!s || !e) return 0;
            var dx = e.screenX - s.screenX, 
                dy = e.screenY - s.screenY;
            return Math.sqrt((dx * dx) + (dy * dy));
        ;
        return new qt();
    
(jQuery));

要使用代码,您可以将其添加到页面中,然后只需监听 quickTap 事件。

<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="quick-tap.js"></script>
<script type="text/javascript">
    $(document).on('quickTap', function(evt, originalEvent) 
        console.log('tap event detected on: ', evt.target.nodeName, 'tag');
    );
</script>

evt 是 quickTap 事件。

evt.target 是被点击的 DOM 元素(不是 jQuery 对象)。

originalEvent 是 qt 判断是否为点击的 touchend 事件。

【讨论】:

【参考方案3】:

您可以在 touchend 事件上隐藏弹出 div。 在touchstart 事件中,您还记得 window.scrollY。 在touchend 事件中,如果scrollY 位置不同,则用户已滚动。

【讨论】:

以上是关于检测用户的意图是点击还是在触觉设备上向上/向下滚动页面的主要内容,如果未能解决你的问题,请参考以下文章

有啥方法可以知道用户是向上还是向下滚动表格视图?在swift IOS中[重复]

如何在移动设备上向上/向下滚动后“显示/隐藏”Bootstrap 3 内容?

js如何判断鼠标滚轮是向下还是向上滚动

在 ListView 中检测向上滚动和向下滚动

如何检测 SwiftUI List 中的向上、向下、顶部和底部滚动

Swift-4 MacOS检测鼠标滚轮滚动到NSTextField?