在移动设备上对抗触摸事件,劫持正常滚动

时间:2014-11-07 09:58:45

标签: javascript mobile scroll touch touch-event

我经历了几次代码,但我找不到基于触摸的设备失败的原因:

    /**
     * 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;
    },

demo(自签名ssl,别担心!):https://sandbox.idev.ge/roomshotel/html5_v3/

问题:触摸时,滚动会直接跳到底部。

预期结果:单触互动等于滚动1个部分。

有什么想法吗?

4 个答案:

答案 0 :(得分:1)

首先,我建议您使用Modernizr来检测触摸

if (Modernizr.touch) {
    $("body").swipe({
        //Generic swipe handler for all directions
        swipe: function (event, direction, distance, duration, fingerCount, fingerData) {
         if(distance >= 100) //Check the units in px or unit
         {
            if (direction === "up") {
                   self.customScrollTo(nextStep);
            } else if (direction === "down") {
                   self.customScrollTo(prevStep);
            }
         }
       }
    });
}

我只是把逻辑放在上面。 “自我”只是你的对象。

要使滑动事件起作用,您必须包含一个jquery插件https://github.com/mattbryson/TouchSwipe-Jquery-Plugin

答案 1 :(得分:0)

我认为事件touchmove多次触发,尝试使用touchend。

关于:http://css-tricks.com/the-javascript-behind-touch-friendly-sliders/ 我已经使用谷歌浏览器实时javascript编辑测试了您的代码。 它在touchmove事件中使用了以下修改。

setTimeout(function(){ self.customScrollTo(nextStep); }, 250);

答案 2 :(得分:0)

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

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

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

  1. 使用var trackPointer = true;之类的标志变量,检查此标志 每次触发touchmove时,将此标志设置为false 指针已走过100px。
  2. 当指针移动100px时, 将startEvent设置为null并检查此变量 touchmove
  3. 指针所在时取消绑定touchmove事件 走了100px。
  4. 注意:每次在此元素上触发 touchmove时,touchstart事件被绑定,这些事件不会相互覆盖但会堆叠!因此,您可能需要考虑仅将事件绑定一次(即,在DOM就绪时)或在不再需要时解除绑定事件。

    后者可能是最简单的,也可以做到,即。 on touchend(使用名称空间只是为了确保不解除绑定其他脚本绑定的相同事件):

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

    当指针移动100px时:

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

    由于当指针位于元素之外时未触发'touchend'(我不确定touchmove),您可能还想在绑定之前解除绑定:

    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];
    

    所以你可以尝试(我没有测试过):

    /**
     * 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)这样的库来使手势在浏览器和非触摸设备上工作。

答案 3 :(得分:0)

/**
 * Initialize touch event listener.
 *
 * @returns {Plugin}
 */

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


        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;

            if (((diff.y <= -100 || diff.y >= 100) && Math.abs(diff.y) > Math.abs(diff.x)) && flag == true) {

                nextStep = diff.y < 0 ? self._currentStep - 1 : self._currentStep + 1;
                self.customScrollTo(nextStep);
                startEvent = event.originalEvent.touches[0];  // Just added this line here.
            }
            event.preventDefault();

            return false;
        });

        return false;
    });

    return this;
},

我想有一个简单的编辑需要。 超过“diff”100或-100之后,只需更新“startEvent”变量的值即可。因此我添加了声明

  startEvent = event.originalEvent.touches[0];

因此,当触发“self.customScrollTo(nextStep)”事件时,“startEvent”值为新值,即触摸点的当前位置。因此,再次调用touchmove事件。它将再次获得一组新的值来计算。 请检查此代码并告诉我这是否有效。即使它不对。