12

Mobile Safari ではdiv、スクロールが端に達したときにページ全体が上下に動くことを許可せずに、絶対に配置されたスクロールを許可することはできますか (弾性スクロール)?

これは、私が直面している問題の最小限の実例です。

<!doctype html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        #a, #b {
            position: absolute;
            top: 0;
            left: 0;
            height: 100%;
            padding: 10px;
            overflow: auto;
        }
        #a {
            width: 80px;
            background: #f00;
        }
        #b {
            background: #00f;
            left: 80px;
            width: 100%;
        }
    </style>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script>
        function pdcb(e) {
            e.preventDefault();
        }
        function npcb(e) {
            e.stopPropagation();
        }
        $(document).on('touchstart touchmove', pdcb).
                    on('touchstart touchmove', '.scrollable', npcb);
    </script>
</head>
<body>
    <div id="a" class="scrollable">
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
    </div>
    <div id="b">
        this should never scroll
    </div>
</body>
</html>

解決:

$(document).on('touchmove', function(e) {
    e.preventDefault();
}).ready(function() {
    $(".scrollable").on('touchstart', function(e) {
        this.allowUp = (this.scrollTop > 0);
        this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight);
        this.prevTop = null;
        this.prevBot = null;
        this.lastY = e.originalEvent.pageY;
    }).on('touchmove', function(e) {
        var event = e.originalEvent;
        var up = (event.pageY > this.lastY), down = !up;
        this.lastY = event.pageY;

        if ((up && this.allowUp) || (down && this.allowDown))
            event.stopPropagation();
        else
            event.preventDefault();
    });
});
4

3 に答える 3

19

元の回答は素晴らしいですが、私が解決したいくつかの欠陥があります。

  • 要素が上または下にある場合、それぞれ上下にスクロールしません。
  • 要素が動的に追加される場合、スクロール ハンドラはありません。
  • 未使用の変数がありました (prevTop、prevBot)

私の答えはそれらに対処します。.scroll-y(の代わりに ,を使用していることに注意してください.scrollable)

まず、次の CSS ルールを追加します。

.scroll-y {
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch; /* nice webkit native scroll */
}

.scroll-yスクロールさせたい要素にクラスを追加します。

次に、この JS をどこかに追加します。

// Disable scroll for the document, we'll handle it ourselves
$(document).on('touchmove', function(e) {
  e.preventDefault();
});

// Check if we should allow scrolling up or down
$(document.body).on("touchstart", ".scroll-y", function (e) {
  // If the element is scrollable (content overflows), then...
  if (this.scrollHeight !== this.clientHeight) {
    // If we're at the top, scroll down one pixel to allow scrolling up
    if (this.scrollTop === 0) {
      this.scrollTop = 1;
    }
    // If we're at the bottom, scroll up one pixel to allow scrolling down
    if (this.scrollTop === this.scrollHeight - this.clientHeight) {
      this.scrollTop = this.scrollHeight - this.clientHeight - 1;
    }
  }
  // Check if we can scroll
  this.allowUp = this.scrollTop > 0;
  this.allowDown = this.scrollTop < (this.scrollHeight - this.clientHeight);
  this.lastY = e.originalEvent.pageY;
});

$(document.body).on('touchmove', ".scroll-y", function(e) {
  var event = e.originalEvent;
  var up = event.pageY > this.lastY;
  var down = !up;
  this.lastY = event.pageY;

  if ((up && this.allowUp) || (down && this.allowDown)) {
    event.stopPropagation();
  } else {
    event.preventDefault();
  }
});
于 2014-02-26T12:26:28.763 に答える
12

div のコンテンツの端に触れていない間は、ネイティブの touchmove イベントがその要素で動作することを許可する必要があります (スクロールできるようにするため)。ページの body でスクロールをトリガーしないこと

要素の境界に到達したら、ネイティブの勢いが完全にスクロールしないようにする必要があります。

これに使用するコードは次のとおりです (元の作成者に謝罪します。これは、過去にインターネット上のどこかで見つけたこのトピックに関するチュートリアルから改作されています...ただし、現在は URL を見つけることができないようです):

elem は DOM ノードです

elem.addEventListener('touchstart', function(event){
    this.allowUp = (this.scrollTop > 0);
    this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight);
    this.prevTop = null; this.prevBot = null;
    this.lastY = event.pageY;
});

elem.addEventListener('touchmove', function(event){
    var up = (event.pageY > this.lastY), down = !up;
    this.lastY = event.pageY;

    if ((up && this.allowUp) || (down && this.allowDown)) event.stopPropagation();
    else event.preventDefault();
});

私は通常、要素の配列を定義し、それらをループして、このコードを各要素に繰り返し適用します。

頑張ってください、これがお役に立てば幸いです。

于 2013-06-03T03:27:34.313 に答える