仅在手势尚未垂直滚动时才允许水平平移事件

时间:2014-11-28 18:05:43

标签: javascript scroll touch hammer.js

我想设置Hammer.js以便我可以响应水平泛事件。我的第一次尝试看起来像这样:

var mc = new Hammer(document.body);
mc.on("panleft panright", runBind(this, 'updatePosition'));
mc.on("panend", runBind(this, 'finalisePosition'));

这几乎得到了我正在寻找的行为:如果我向左或向右平移,则调用updatePosition函数,当我停止平移时,调用finalisePosition函数。

但是如果手势在垂直滚动时向左或向右偏移,也会触发这些功能。例如,假设我触摸屏幕顶部附近,然后将手指向下拖动到屏幕的一半:这应该注册为滚动事件。现在假设我继续通过对角线拖动:向下和向左拖动。在这种情况下,我想忽略手势的水平部分,并将手势仅视为垂直滚动事件,但Hammer.js会像以前一样触发panrightpanleft事件。 / p>

我的下一次尝试看起来像这样:

var mc = new Hammer(document.body, {
  recognizers: [
    [Hammer.Swipe],
    [
      Hammer.Pan,
      {event: 'panvertical', direction: Hammer.DIRECTION_VERTICAL}
    ],
    [
      Hammer.Pan,                               // RecognizerClass
      {direction: Hammer.DIRECTION_HORIZONTAL}, // options
      ['swipe'],                                // recognizeWith
      ['panvertical']                           // requireFailure
    ],
  ]
});
mc.on("panleft panright", runBind(this, 'updatePosition'));
mc.on("panend", runBind(this, 'finalisePosition'));

这指定仅在panvertical事件失败时才触发水平平移事件。果然,这可以防止我上面描述的问题。如果我开始垂直滚动手势然后开始水平移动,则不会触发panleftpanright事件。但是这个版本有一个更严重的探测:默认的滚动行为不会发生!因此,无法滚动应用程序。

有人能提出更好的解决方案吗?

我正在使用Hammer.js版本2.0.4。

3 个答案:

答案 0 :(得分:0)

我遇到了同样的问题 我设法使用这个非常丑陋的代码

   var first = false, lock = false;
   var containerHandler = function(event) {

       if(event.type == 'panend' || event.type == 'pancancel') {
         // iOS bug fix
         lock = false;
         first = false;

       } else if(event.type == 'swipe' && event.direction & Hammer.DIRECTION_VERTICAL) {
         // iOS bug fix
         lock = true;
         first = true;
       }
       else if(event.type == 'panmove') {
         // iOS bug fix ... 
         if(first === false && event.direction & Hammer.DIRECTION_VERTICAL) {
           lock = true;
         }

         first = true;
         if(lock === true)
         return;

         //your code etc...
    };

    var focusMC = new Hammer.Manager(mainContainer[0], {domEvents:true});
    var pan = new Hammer.Pan({threshold: 5, direction:Hammer.DIRECTION_HORIZONTAL});
    focusMC.add( pan );
    focusMC.on('panstart panmove panend pancancel swipe', containerHandler);

小门槛很重要..

据我记得,此问题仅适用于iOS Safari,但在WP上即使没有此代码也能正常工作

修改:而不是上面的解决方案,请尝试强制touch-action属性 到pan-y

我保留两个答案,因为它们应该全部工作

答案 1 :(得分:0)

Hammer.js将根据您的识别器自动推断触摸操作属性。这可能会使应用程序更具响应性,但它​​不会仅仅因为用户与元素交互而阻止垂直页面滚动。

我遇到了同样的问题,并找到了一个非常简单的解决方案,可以很好地解决问题。

var isScrolling = false;

var galleryHammer = new Hammer(element, {
    recognizers: [
        [Hammer.Pan, { direction: Hammer.DIRECTION_HORIZONTAL }]
    ]
});

// Making the event listener passive means we don't get any delays between
// the user scrolling and the browser having checked if it should prevent
// that event
window.addEventListener('scroll', function() {
    isScrolling = true;
}, { passive: true });

window.addEventListener('touchend', function() {
    isScrolling = false;
});

galleryHammer.on('pan', function(event) {
    if (isScrolling) {
        return;
    }

    // Normal logic...
});

答案 2 :(得分:0)

这对我有用(代码来自一个类,而this.hm只是Hammer实例):

this.hm.on('panleft', function(e){ // ...and same for panright
   if(e.pointerType == 'touch' && (Math.abs(e.deltaY) > Math.abs(e.deltaX))){ return false; }
   // do stuff
}

因为我在台式机上没有任何问题(鼠标事件),所以进行了额外的pointerType检查。因此,整个过程仅适用于触摸设备/事件。