107

私は iPad ベースの Web アプリに取り組んでおり、Web ページのように見えないようにオーバースクロールを防ぐ必要があります。現在、これを使用してビューポートをフリーズし、オーバースクロールを無効にしています:

document.body.addEventListener('touchmove',function(e){
      e.preventDefault();
  });

これはオーバースクロールを無効にするのに最適ですが、私のアプリにはいくつかのスクロール可能な div があり、上記のコードはスクロールを妨げます

私は iOS 5 以降のみをターゲットにしているので、iScroll のようなハックなソリューションは避けてきました。代わりに、スクロール可能な div にこの CSS を使用しています。

.scrollable {
    -webkit-overflow-scrolling: touch;
    overflow-y:auto;
}

これは、ドキュメント オーバースクロール スクリプトがなくても機能しますが、div スクロールの問題は解決しません。

jQuery プラグインがなければ、オーバースクロール修正を使用して $('.scrollable') div を除外する方法はありますか?

編集:

私はまともな解決策である何かを見つけました:

 // Disable overscroll / viewport moving on everything but scrollable divs
 $('body').on('touchmove', function (e) {
         if (!$('.scrollable').has($(e.target)).length) e.preventDefault();
 });

div の先頭または末尾を超えてスクロールしても、ビューポートは移動します。それを無効にする方法も見つけたいと思います。

4

15 に答える 15

84

これにより、div の先頭または末尾を超えてスクロールするときの問題が解決されます。

var selScrollable = '.scrollable';
// Uses document because document will be topmost level in bubbling
$(document).on('touchmove',function(e){
  e.preventDefault();
});
// Uses body because jQuery on events are called off of the element they are
// added to, so bubbling would not work if we used document instead.
$('body').on('touchstart', selScrollable, function(e) {
  if (e.currentTarget.scrollTop === 0) {
    e.currentTarget.scrollTop = 1;
  } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) {
    e.currentTarget.scrollTop -= 1;
  }
});
// Stops preventDefault from being called on document if it sees a scrollable div
$('body').on('touchmove', selScrollable, function(e) {
  e.stopPropagation();
});

div にオーバーフローがない場合にページ全体のスクロールをブロックしたい場合、これは機能しないことに注意してください。それをブロックするには、すぐ上のイベント ハンドラーの代わりに次のイベント ハンドラーを使用します (この質問から適応)。

$('body').on('touchmove', selScrollable, function(e) {
    // Only block default if internal div contents are large enough to scroll
    // Warning: scrollHeight support is not universal. (https://stackoverflow.com/a/15033226/40352)
    if($(this)[0].scrollHeight > $(this).innerHeight()) {
        e.stopPropagation();
    }
});
于 2013-01-09T19:12:47.947 に答える
23

Tyler Dodge の優れた回答を使用すると、iPad で処理が遅れていたので、スロットリング コードを追加しました。今では非常にスムーズです。スクロール中に最小限のスキップが発生することがあります。

// Uses document because document will be topmost level in bubbling
$(document).on('touchmove',function(e){
  e.preventDefault();
});

var scrolling = false;

// Uses body because jquery on events are called off of the element they are
// added to, so bubbling would not work if we used document instead.
$('body').on('touchstart','.scrollable',function(e) {

    // Only execute the below code once at a time
    if (!scrolling) {
        scrolling = true;   
        if (e.currentTarget.scrollTop === 0) {
          e.currentTarget.scrollTop = 1;
        } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) {
          e.currentTarget.scrollTop -= 1;
        }
        scrolling = false;
    }
});

// Prevents preventDefault from being called on document if it sees a scrollable div
$('body').on('touchmove','.scrollable',function(e) {
  e.stopPropagation();
});

また、次の CSS を追加すると、レンダリングの不具合が修正されます ( source )。

.scrollable {
    overflow: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
}
.scrollable * {
    -webkit-transform: translate3d(0,0,0);
}
于 2013-01-21T22:25:50.057 に答える
13

まず、通常どおり、ドキュメント全体に対するデフォルトのアクションを防止します。

$(document).bind('touchmove', function(e){
  e.preventDefault();           
});

次に、要素のクラスがドキュメントレベルに伝播するのを停止します。これにより、上記の関数に到達できなくなり、e.preventDefault()は開始されません。

$('.scrollable').bind('touchmove', function(e){
  e.stopPropagation();
});

このシステムは、すべてのタッチムーブでクラスを計算するよりも自然で集中力が低いようです。動的に生成される要素には、.bind()ではなく.on()を使用します。

また、スクロール可能なdivの使用中に不幸なことが起こらないように、これらのメタタグを検討してください。

<meta content='True' name='HandheldFriendly' />
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0' name='viewport' />
<meta name="viewport" content="width=device-width" />
于 2013-03-02T15:19:20.067 に答える
7

オーバースクロールを無効にするコードにもう少しロジックを追加して、問題のターゲット要素がスクロールしたいものではないことを確認できますか? このようなもの:

document.body.addEventListener('touchmove',function(e){
     if(!$(e.target).hasClass("scrollable")) {
       e.preventDefault();
     }
 });
于 2012-05-02T04:16:09.693 に答える
5

スクロール可能な要素が、上にスクロールしようとしたときにすでに上にスクロールされているか、下にスクロールしようとしているときに下にスクロールされているかどうかを確認し、デフォルトのアクションがページ全体の移動を停止するのを防ぎます。

var touchStartEvent;
$('.scrollable').on({
    touchstart: function(e) {
        touchStartEvent = e;
    },
    touchmove: function(e) {
        if ((e.originalEvent.pageY > touchStartEvent.originalEvent.pageY && this.scrollTop == 0) ||
            (e.originalEvent.pageY < touchStartEvent.originalEvent.pageY && this.scrollTop + this.offsetHeight >= this.scrollHeight))
            e.preventDefault();
    }
});
于 2012-05-31T14:15:47.927 に答える
4

スクロール可能な領域を持つポップアップ(カートのスクロール可能なビューを持つ「ショッピングカート」ポップダウン)があるときに、すべてのボディスクロールを防ぐ方法を探していました。

スクロールしたいポップアップまたはdivがある場合に、最小限のjavascriptを使用して、ボディのクラス「noscroll」を切り替えるだけのはるかにエレガントなソリューションを作成しました(ページボディ全体を「オーバースクロール」しません)。

デスクトップブラウザはoverflow:hiddenを観察しますが、位置を固定に設定しない限り、iOSはそれを無視するようです...ページ全体が奇妙な幅になるため、位置と幅も手動で設定する必要があります。このCSSを使用してください:

.noscroll {
    overflow: hidden;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
}

そしてこのjquery:

/* fade in/out cart popup, add/remove .noscroll from body */
$('a.cart').click(function() {
    $('nav > ul.cart').fadeToggle(100, 'linear');
    if ($('nav > ul.cart').is(":visible")) {
        $('body').toggleClass('noscroll');
    } else {
        $('body').removeClass('noscroll');
    }
});

/* close all popup menus when you click the page... */
$('body').click(function () {
    $('nav > ul').fadeOut(100, 'linear');
    $('body').removeClass('noscroll');
});

/* ... but prevent clicks in the popup from closing the popup */
$('nav > ul').click(function(event){
    event.stopPropagation();
});
于 2013-09-20T17:57:07.877 に答える
0

これを試してみてください。完璧に動作します。

$('body.overflow-hidden').delegate('#skrollr-body','touchmove',function(e){
    e.preventDefault();
    console.log('Stop skrollrbody');
}).delegate('.mfp-auto-cursor .mfp-content','touchmove',function(e){
    e.stopPropagation();
    console.log('Scroll scroll');
});
于 2016-06-28T11:57:44.570 に答える
0

これがゼプト互換のソリューションです

    if (!$(e.target).hasClass('scrollable') && !$(e.target).closest('.scrollable').length > 0) {
       console.log('prevented scroll');
       e.preventDefault();
       window.scroll(0,0);
       return false;
    }
于 2013-02-18T05:34:35.007 に答える