简体   繁体   English

有没有办法防止fastclick在滚动时触发“活动”状态?

[英]Is there a way to prevent fastclick from firing “active” state on scroll?

I'm using FastClick on a page with large links because I want to bypass the 300ms delay for taps in mobile browsers. 我在具有大链接的页面上使用FastClick ,因为我想在移动浏览器中绕过300ms的点击延迟。 I have a “highlight” style for the links' :active states and it is properly firing quickly, thanks to FastClick. 我有一个“突出”样式的链接' :active状态,它正在快速正确触发,感谢FastClick。

My problem is that – in Mobile Safari at least – it also fires while you're tapping and swiping to scroll the page. 我的问题是 - 至少在Mobile Safari中 - 当你点击和滑动以滚动页面时它也会触发。 This makes it feel like you can't scroll the page without it thinking you're trying to tap the links. 这使得您觉得无法在不考虑点击链接的情况下滚动页面。

Is there a way to prevent it from firing when someone scrolls? 当有人滚动时,有没有办法阻止它发射?

Maybe you can add the needsclick class to the body? 也许你可以将needsclick类添加到正文中?

<body class="needsclick">

...

</body>

Just an idea :) 只是一个想法:)

Nice question! 好问题! +1 +1

This problem has nothing to do with FastClick, but FastClick does make the solution to your problem more complex. 此问题与FastClick无关,但FastClick确实使您的问题的解决方案更加复杂。 So I will stick to pure JavaScript and raw Touch Events ) 所以我将坚持纯JavaScript和原始触摸事件)

On a mobile touch device the implementation of the webview is significantly different from the desktop web browser for reasons specific to the platform. 在移动触摸设备上,由于特定于平台的原因,webview的实现与桌面web浏览器显着不同。 One feature that is important in this case is momentum scrolling in the webview. 在这种情况下,一个重要的功能是webview中的动量滚动。 Momentum Scrolling is a hardware accelerated feature of the device. Momentum Scrolling是设备的硬件加速功能。 So when a scrollable area is touched on the screen, the hardware identifies the touch and attaches a 200 millisecond countdown timer to the scrollable area, that when triggered, puts the area into a hardware accelerated scroll. 因此,当在屏幕上触摸可滚动区域时,硬件识别触摸并将200毫秒倒数计时器附加到可滚动区域,当触发时,将该区域置于硬件加速滚动中。 When the hardware is in the state it does not broadcast touch events because they are specific to the hardware accelerated scroll. 当硬件处于状态时,它不会广播触摸事件,因为它们特定于硬件加速滚动。 The timer can be cancelled, and momentum scrolling prevented by using preventDefault on the touch event within the provided 200 milliseconds. 可以取消计时器,并通过在提供的200毫秒内对触摸事件使用preventDefault来防止动量滚动。

Here is how I approach this problem. 这是我如何处理这个问题。 I assume you are using native scroll ie overflow:scroll . 我假设您正在使用本机滚动即overflow:scroll The method is to attach a touchstart event to the element you want touchable. 该方法是将touchstart事件附加到您想要可触摸的元素。 Once the touchstart event has fired, the event handler attaches touchend , touchmove and touchcancel events to the target element. touchstart事件触发后,事件处理程序touchendtouchmovetouchcancel事件附加到目标元素。 A setTimout timer is initiated that removes the newly added events after 140ms. 启动setTimout计时器,在140ms后删除新添加的事件。

Here are some clips for my production code: I have two event methods for adding and removing events from collections: 以下是我的生产代码的一些剪辑:我有两种事件方法可以添加和删除集合中的事件:

var eventify = (function () {
    function eventify(type, el, callback, phase) {
        phase = phase || false;
        if ((el.constructor.toString().contains('NodeList')) || (el.constructor.toString().contains('HTMLCollection'))) {
            [].forEach.call(el, function (element) {
                if (!element.hasEvent(type)) {
                    element.addEvent(type);
                    HTMLElement.prototype.addEventListener.apply(element, [type, callback, phase]);
                }
            });
        } else {
            if (!el.hasEvent(type)) {
                el.addEvent(type);
                HTMLElement.prototype.addEventListener.apply(el, [type, callback, phase]);
            }
        }
        return callback;
    }

    return eventify
})();

var uneventify = (function () {
    function uneventify(type, el, callback) {
        if ((el.constructor.toString().contains('NodeList')) || (el.constructor.toString().contains('HTMLCollection'))) {
            [].forEach.call(el, function (element) {
                if (element.hasEvent(type)) {
                    element.removeEvent(type);
                    HTMLElement.prototype.removeEventListener.apply(element, [type, callback]);
                }
            });
        } else {
            if (el.hasEvent(type)) {
                el.removeEvent(type);
                HTMLElement.prototype.removeEventListener.apply(el, [type, callback]);
            }
        }
    }

    return uneventify
})();

Then I have a tapify method for tap events on the scroller: 然后我在滚动条上有一个tapify方法来点击事件:

var tapify = (function () {
    function tapify(el, callback) {
        eventify('touchstart', el, function (e) {
            var that = this;
            var start = e.pageY;
            var target = e.target;
            function dynamicEvents() {
                var endfn = eventify('touchend', target, function (evt) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                    evt.preventDefault();
                    evt.stopImmediatePropagation();
                    uneventify('touchmove', target, movefn);
                    uneventify('touchend', target, endfn);
                    uneventify('touchcancel', target, cancelfn);
                    callback && callback(target);
                });
                var cancelfn = eventify('touchcancel', target, function (evt) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                    evt.preventDefault();
                    evt.stopImmediatePropagation();
                    uneventify('touchmove', target, movefn);
                    uneventify('touchend', target, endfn);
                    uneventify('touchcancel', target, cancelfn);
                    callback && callback(target);
                });
                var movefn = eventify('touchmove', target, function (evt) {
                    var distance = start - evt.pageY;
                    if (distance > 20) {
                        uneventify('touchend', target, endfn);
                        uneventify('touchcancel', target, cancelfn);
                        uneventify('touchmove', el, movefn);
                    }
                });
                setTimeout(function () {
                    uneventify('touchmove', target, movefn);
                    uneventify('touchend', target, endfn);
                    uneventify('touchcancel', target, cancelfn);
                }, 140);
            }
            if (global.isIos) setTimeout(function () {
                dynamicEvents();
            }, 60);
            else dynamicEvents();
        }, false);
    }
    return tapify;
})();

I use global.isIos to identify the target device. 我使用global.isIos来识别目标设备。 Android stops sending touch events to webview ater 200ms. Android会停止向webview发送触摸事件200ms。

Then to attach the event to a element or a collection of elements, use : 然后,要将事件附加到元素或元素集合,请使用:

tapify(document.querySelectorAll('button'), function (e) {
      //your event handler here!! 
});

Hope this helps 希望这可以帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM