应对移动设备上的触摸事件,劫持正常滚动 [英] fighting touch events on mobile devices, highjacking normal scroll

查看:86
本文介绍了应对移动设备上的触摸事件,劫持正常滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我多次检查了代码,但找不到基于触摸设备的代码失败的原因:

I went through the code several times and I cannot find the reason it fails on touch based devices:

    /**
     * Initialize touch event listener.
     *
     * @returns {Plugin}
     */
    touch: function () {
        var self = this;

        this._$body.bind('touchstart', function (event) {
            var startEvent = event.originalEvent.touches[0];

            event.preventDefault();
            self._$body.bind('touchmove', function (event) {
                var moveEvent = event.originalEvent.touches[0];
                var diff = { x: startEvent.clientX - moveEvent.clientX, y: startEvent.clientY - moveEvent.clientY };
                var nextStep;
                event.preventDefault();
                if ((diff.y <= -100 || diff.y >= 100) && Math.abs(diff.y) > Math.abs(diff.x)) {
                    nextStep = diff.y < 0 ? self._currentStep - 1 : self._currentStep + 1;
                    self.customScrollTo(nextStep);
                }
                return false;
            });

            return false;
        });

        return this;
    },

演示(自签名的ssl,请放心!): https://sandbox.idev. ge/roomshotel/html5_v3/

demo (self signed ssl, don't worry!): https://sandbox.idev.ge/roomshotel/html5_v3/

问题:激活触摸后,滚动会直接跳到底部.

Problem: Scroll jumps straight to bottom when touch is activated.

预期结果:一键互动相当于滚动了1个部分.

Expected result: One touch interaction equals 1 section scrolled.

有什么想法吗?

推荐答案

我也认为touchmove事件的回调在每次触摸时都会触发.通过从该函数返回false,您只能取消该单个触摸移动事件,而不能取消所有随后的触摸移动事件.

I too think the touchmove event's callback is being fired on every touch move. By returning false from that function you only cancel that single touch move event and not all following touch move events.

您不能使用touchend事件,因为您希望在指针移动100px后立即调用self.customScrollTo(nextStep);.

You cannot use a touchend event since you want to call self.customScrollTo(nextStep); as soon as the pointer has travelled 100px.

您希望阻止在指针移动100px之后执行touchmove回调,这可以通过多种方式完成,例如.

You want to prevent your touchmove callback from being executed after the pointer has travelled 100px, this can be done in many ways, ie.

  1. 使用像var trackPointer = true;这样的标志变量,检查该标志 每次触发touchmove时,当 指针已移动100像素.
  2. 当指针移动100像素时, 将startEvent设置为null并在 touchmove.
  3. 当指针具有touchmove事件时解除绑定 跑了100像素.
  1. Using a flag variable like var trackPointer = true;, check this flag each time touchmove is being triggered and set this flag to false when the pointer has travelled 100px.
  2. When the pointer has travelled 100px, set the startEvent to null and check this variable on touchmove.
  3. Unbind the touchmove event when the pointer has travelled 100px.

NB:touchmove事件被绑定每次 touchstart都在此元素上触发,这些事件不会互相覆盖但会堆叠在一起!因此,您可能想考虑只绑定一次事件(即在DOM就绪时),或者在不再需要时取消绑定事件.

NB: The touchmove event is being bound each time touchstart is triggered on this element, these events do not overwrite each other but get stacked! So you might want to consider binding the event only once (ie. on DOM ready) or unbind the event when it's no longer necessary.

后者可能是最简单的,可以做到.在touchend上(使用名称空间只是为了确保不取消绑定其他脚本绑定的相同事件):

The latter is probably the easiest and could be done ie. on touchend (use namespaces just to be sure to not unbind the same events bound by other scripts):

// Unbind all touchmove.myNameSpace events on touchend.myNameSpace.
self._$body.bind('touchend.myNameSpace').function (event) {
  self._$body.unbind('touchmove.myNameSpace');
});

,并且当指针移动了100px时:

and when the pointer has travelled 100px:

self.customScrollTo(nextStep);
// Unbind all touchmove.myNameSpace events.
self._$body.unbind('touchmove.myNameSpace');

由于当指针位于元素外部时不会触发"touchend"(我不确定touchmove),因此您可能还想在绑定之前取消绑定:

Since 'touchend' is not triggered when the pointer is outside the element (I am not sure about touchmove), you might also want to unbind right before binding:

event.preventDefault();
// Unbind all touchmove.myNameSpace events and (re)bind touchmove.myNameSpace event.
self._$body.unbind('touchmove.myNameSpace').bind('touchmove.myNameSpace', function (event) {
  var moveEvent = event.originalEvent.touches[0];

因此您可以尝试(我尚未测试过):

So you could try (I have not tested it):

/**
 * Initialize touch event listener.
 *
 * @returns {Plugin}
 */
touch: function () {
    var self = this;

    this._$body.bind('touchstart', function (event) {
        var startEvent = event.originalEvent.touches[0];

        event.preventDefault();
        self._$body.unbind('touchmove.myNameSpace').bind('touchmove.myNameSpace', function (event) {
            var moveEvent = event.originalEvent.touches[0];
            var diff = { x: startEvent.clientX - moveEvent.clientX, y: startEvent.clientY - moveEvent.clientY };
            var nextStep;
            event.preventDefault(); // <- Not necessary since you completely cancel the event by returning false.
            if ((diff.y <= -100 || diff.y >= 100) && Math.abs(diff.y) > Math.abs(diff.x)) {
                nextStep = diff.y < 0 ? self._currentStep - 1 : self._currentStep + 1;
                self.customScrollTo(nextStep);

                // Unbind all touchmove.myNameSpace events.
                self._$body.unbind('touchmove.myNameSpace');
            }
            return false;
        });

        return false;
    });

    // Unbind all touchmove.myNameSpace events on touchend.myNameSpace.
    self._$body.bind('touchend.myNameSpace').function (event) {
        self._$body.unbind('touchmove.myNameSpace');
    });

    return this;
},

PS:您可能希望使用HammerJS之类的库( https://github.com/hammerjs/Hammer.js ),使手势可以在浏览器上以及在非触摸设备上正常工作.

PS: You might want to use a library like HammerJS (https://github.com/hammerjs/hammer.js) to make gestures work cross browser and also on non-touch devices.

这篇关于应对移动设备上的触摸事件,劫持正常滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆