如何在不阻止触摸启动的情况下防止'Overscroll history navigation'?



我正在实现滑动导航,我在Chrome上遇到了麻烦。

一个新实现的功能,"超滚动历史导航",当页面被拖到右边时触发,导致跳回("历史-1")。为了防止这种情况,我必须在touchstart上调用.preventDefault(),但这也禁用了从点击链接到滚动的所有操作。如何在不干扰标准页面的情况下防止浏览器UI事件?

通过在chrome中设置适当的标志来完全禁用该功能可以解决这个问题,但对于面向公众的应用程序来说是不切实际的。chrome://标志/# overscroll-history-navigation

我终于想出了一个解决办法:

Chrome在过度滚动之前至少触发touchstarttouchmove。通过跟踪这些事件的方向,可以从常规滚动中过滤出过度滚动。

我已经为这个Hammer.js问题写好了代码

要保持垂直滚动工作和水平移动元素,您需要通过使用Math.abs()比较坐标差异来检查移动是否更多地沿着x轴而y轴,然后决定是否在touchmove事件中调用. preventdefault ()

听起来有点奇怪,但我认为这是唯一的方法来控制这个庞然大物的功能"滚动历史导航"。祝福。

$(function () {
    function extract(e) {
        if (e.changedTouches) {
            e = e.changedTouches;
            if (e['0'])
                e = e['0'];
        }
        return e;
    }
    var div = $('div').html('Drag me left and right and see that Overscroll is disabled & drag me up and down to see that scroll still works<br /><br /><br />'.repeat(300));
    var di  = div.get(0); // get native dom element
    var startx, lastx, lasty, l = false, active = false;
    di.addEventListener("touchstart", function (e) {
        active = true;
        e = extract(e);
        // init
        lastx = e.pageX;
        lasty = e.pageY;
        l = parseInt(div.css('left'), 10);
        startx = e.pageX;
    }, false);
    di.addEventListener("touchmove", function (ee) {
        if (active) {
            var e = extract(ee);
            // check if preventDefault to cancel Overscroll history navigation only if it's needed
            if (Math.abs(lastx - e.pageX) > Math.abs(lasty - e.pageY)) {
                ee.preventDefault();
            }
            // update x y to next above calculation
            lastx = e.pageX;
            lasty = e.pageY;
            // repositioning
            div.css({left: (l + (e.pageX - startx))+'px'})
        }
    }, false);
    di.addEventListener("touchend", function (e) {
        active = false;
    }, false);
});

完整的触摸设备测试示例:DEMO

  • 监听容器上的onscroll事件并存储'scrollLeft'值this.offsetX = event.currentTarget.scrollLeft;
  • 监听同一容器上的onwheel事件并使用此处理程序

var offset = 0;
document.getElementById("1")
  .addEventListener("scroll", function(event) {
     offset = event.currentTarget.scrollLeft;
  });
document.getElementById("1")
  .addEventListener("wheel", function(event) {
    // if we reach the left side of the scrollable content, and we scroll further -> block the event
    if (offset === 0 && event.deltaX <= 0) {
      event.preventDefault();
    }
  });
  
  
.container {
  width: 100%;
  background-color: blue;
  overflow: auto;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}
.element {
  display: inline-block;
  min-width: 100px;
  height: 50px;
  margin: 10px;
  background-color: red;
}
<div id="1" class="container">
  <div class="element">
  1
  </div>
  <div class="element">
  2
  </div>
  <div class="element">
  3
  </div>
  <div class="element">
  4
  </div>
  <div class="element">
  5
  </div>
  <div class="element">
  6
  </div>
  <div class="element">
  7
  </div>
  <div class="element">
  8
  </div>
</div>

我用

html, body {
    width: 100%;
    height: 100%;
    margin: 0;
    overscroll-behavior: contain;    
}
https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior

这是'touchmove'你将不得不stopPropagation()和preventDefault()内的回调,你可以调用任何你需要检查滑动和导航发生

最新更新