【问题标题】:How to prevent 'Overscroll history navigation' without preventing touchstart?如何在不阻止触摸启动的情况下防止“过度滚动历史导航”?
【发布时间】:2014-05-09 09:00:18
【问题描述】:

我正在实现滑动式导航,但我在使用 Chrome 时遇到了麻烦。

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

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

【问题讨论】:

  • 你有没有发现这个问题。我整天都在谷歌上搜索,却找不到任何地方。
  • 是的,我已将其添加为答案。

标签: javascript google-chrome touch preventdefault


【解决方案1】:

我最终想出了一个解决方案:

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

我已经写好了代码for this Hammer.js issue

【讨论】:

    【解决方案2】:

    我用过

    html, body {
        width: 100%;
        height: 100%;
        margin: 0;
        overscroll-behavior: contain;    
    }
    

    https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior

    【讨论】:

    • 遗憾的是,这对我不起作用。我尝试将它设置在正文和可滚动元素(水平滚动列表)上,包含和无。但它一直在导航。有趣的是,当我做出快速手势时,它在我过度滚动(到达列表的开头)之前就做到了。在 Chrome 中似乎不仅仅是过度滚动导致此问题。
    【解决方案3】:

    要让滚动垂直工作和水平移动元素,您需要通过使用 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

    【讨论】:

      【解决方案4】:
      • 监听容器上的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>

      【讨论】:

        【解决方案5】:

        它是“touchmove”,你必须在回调中调用 stopPropagation() 和 preventDefault(),你可以调用任何你需要的东西来检查滑动和导航是否发生。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-06-22
          • 1970-01-01
          • 2011-10-27
          • 2011-09-15
          • 2014-01-04
          • 1970-01-01
          • 1970-01-01
          • 2016-03-05
          相关资源
          最近更新 更多