【问题标题】:fighting touch events on mobile devices, highjacking normal scroll在移动设备上对抗触摸事件,劫持正常滚动
【发布时间】:2015-01-04 02:06:06
【问题描述】:

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

    /**
     * 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 个部分。

有什么想法吗?

【问题讨论】:

  • 滚动对我来说根本不起作用
  • 普通滚动在 Chrome 中不起作用,触摸在移动 safari 中不起作用
  • @salivan 给我一些时间,我会试着弄清楚。顺便说一句,如果你继续设置这么多的赏金,你很快就会用完你的回购))
  • @SamBraslavskiy 好吧,这些都是棘手的问题,所以我认为让他们成为正常点问题对你们来说不合适......我正在为这些情况积累 REP :)
  • 不知何故,其中很多 .jpg 和 .svg 不适合我。不过不知道是不是我一个人。

标签: javascript mobile scroll touch touch-event


【解决方案1】:

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

关于:http://css-tricks.com/the-javascript-behind-touch-friendly-sliders/ 我已经用 google chrome live javascript edit 测试了你的代码。 它在 touchmove 事件中进行了以下修改。

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

【讨论】:

    【解决方案2】:

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

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

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

    1. 使用像var trackPointer = true;这样的标志变量,检查这个标志 每次触发touchmove 并将此标志设置为false 时 指针已移动 100 像素。
    2. 当指针移动 100px 时, 将startEvent 设置为null 并检查此变量 touchmove
    3. 当指针有时解除touchmove事件的绑定 移动了 100 像素。

    注意:touchmove 事件正在被绑定每次 touchstart 在此元素上被触发,这些事件不会相互覆盖而是堆叠!因此,您可能需要考虑只绑定一次事件(即在 DOM 就绪时)或在不再需要时取消绑定事件。

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

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

    当指针移动 100 像素时:

    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】:

      首先我会建议你使用 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);
                  }
               }
             }
          });
      }
      

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

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

      【讨论】:

      • 嗅探触摸是不可靠的,因为现在的设备可以同时支持鼠标和触摸(Chromebook 和许多 W8 PC),并且一些设备确实支持触摸但没有连接触摸设备,因此结果误报。
      【解决方案4】:
      /**
       * 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;
      },
      

      我想需要进行简单的编辑。 在您超过“差异”100 或-100 之后,只需更新“startEvent”变量的值。因此我添加了语句

        startEvent = event.originalEvent.touches[0];
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-09
        • 1970-01-01
        • 1970-01-01
        • 2019-04-03
        • 2023-03-18
        • 1970-01-01
        • 2014-01-04
        • 1970-01-01
        相关资源
        最近更新 更多