【问题标题】:Prevent vertical mobile scrolling on predominantly horizontal touch gesture in JavaScript防止在 JavaScript 中以水平触摸手势为主的垂直移动滚动
【发布时间】:2018-08-17 02:39:24
【问题描述】:

我有一些 JavaScript 来处理网页上的触摸事件并观察主要是水平的手势。当用户开始水平滑动时,我希望他们的手势效果开始,但是当他们垂直滑动时,页面应该自然滚动。

虽然现在水平手势确实获得了预期的效果,但它们似乎仍然会导致垂直滚动触摸向上或向下移动的量,即使大部分移动是水平的。当主要水平滑动时,我将如何解决此问题以防止垂直滚动?我同时使用了preventDefault()stopPropagation() 都没有效果。我想我错过了一些非常明显的东西,但我似乎找不到它。

我已尽力搜索类似问题,但我的搜索查询尚未返回 anything that works

注意:我不想完全停止垂直滚动,即使手势中的 X 值发生变化,如果 Y 变化更大,页面仍应滚动。如果 X 变化大于 Y 变化(这是我的代码现在应该做的),我只希望垂直滚动锁定。

更新:我没想过要从移动设备检索控制台日志记录。在@tushar-shukla 的建议下,我检查了它,发现以下错误:

[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See <URL>

这是我的代码(和a JSFiddle, if that's more your cup of tea)的淡化版本:

var startX = undefined;
var startY = undefined;

function touchmove(ev) {
    var e = ev.originalEvent;

    // Set the initial start position if not already. Could also be done on touchstart
    if (startX===undefined) { startX=e.touches[0].pageX; }
    if (startY===undefined) { startY=e.touches[0].pageY; }

    // Calculate the change or displacement from the start.
    changeX = e.touches[0].pageX-startX;
    changeY = e.touches[0].pageY-startY;

    // If the change horizontally is greater than the change vertically...
    if (Math.abs(changeX)>Math.abs(changeY)) {

        // Do something with the gesture

        // Prevent vertical scrolling; Apparently this isn't doing it:
        ev.preventDefault();
        ev.stopPropagation();
        e.preventDefault();
        e.stopPropagation();

    }
}

$(document).on("touchmove",touchmove);

【问题讨论】:

    标签: javascript jquery


    【解决方案1】:

    将我的移动设备连接到 Chrome 后,我检索了控制台日志记录,其中包含以下重复错误:

    [Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See <URL>
    

    这是我解决问题所需的线索。现代移动浏览器有passive and active event listeners,主动浏览器可以阻止事件的默认操作,而被动浏览器则不能。这是针对触摸手势之类的性能优化,需要尽可能流畅地运行,即使在庞大的网页上也是如此。

    JavaScript 自动为 touchmove 等事件使用被动事件侦听器。虽然 JavaScript 在附加事件侦听器以更改此行为时提供了一个参数,但 jQuery,不幸的是,does not

    当然,这意味着问题可以通过替换来轻松解决:

    $(document).on("touchmove",touchmove);
    

    在我的代码中:

    document.addEventListener('touchmove', pageswiping.touchmove, {passive: false});
    

    在这种情况下,{passive: false} 清楚地表明事件侦听器是主动的,而不是被动的。

    【讨论】:

      【解决方案2】:

      如果我理解正确,当用户水平滚动(或尝试)时,您需要停止垂直滚动(这是无意的)。

      我还没有测试过,但可能这可以工作。

      var startX;
      $(document).on('touchstart', function(e) {
        startX = e.originalEvent.touches[0].clientX;
      });
      
      $(document).on('touchmove', function(e) {
        var endX = e.originalEvent.changedTouches[0].clientX;
        if (startX !== endX) {
          console.log('attempting horizontal scroll');
          e.preventDefault();
        }
      });
      

      【讨论】:

      • 恐怕这已经是我正在尝试的,只是在更少的行中(做得很好!)。似乎e.preventDefault() 无法停止滚动。请在移动设备上检查您的代码,但据我所知,这并没有更好... :/ 另请注意,您必须检查 X-change 是否大于 Y-变化,因为通常旨在滚动的手势并不完全是上下。
      • 恐怕我现在无法测试,但你可以试试touch-action: none;position: fixed;overflow: hidden; 另外,请注意我已经通过touchstart 事件捕获了开始事件为了精确,可能会有一些好处。就preventDefault 而言,它应该已经完成​​了这项工作,但是既然你说它不起作用,那么console.log() 中是否有任何错误?
      • 啊,谢谢你建议检查控制台日志...我真的应该早点检查一下,但也没有手边的移动设备。
      猜你喜欢
      • 2012-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多