27

これ:

$('body').on('touchmove', function(e) { e.preventDefault(); });

機能しますが、ページ全体のスクロールが無効になり、理想とはほど遠いものになります。

これ:

$('*').on('touchstart', function(e){
    var element = $(this).get(0);

    if ( element.scrollTop <= 0 )                                           element.scrollTop = 1;
    if ( element.scrollTop + element.offsetHeight >= element.scrollHeight ) element.scrollTop = element.scrollHeight - element.offsetHeight - 1;
});

スクロール領域のあるページで機能します。ただし、スクロールするものが何もない場合は、再びラバーバンドが表示されます。

だから私の質問:

-webkit-overflow-scrollingラバーバンド効果を無効にして、領域をスクロール可能にするにはどうすればよいですか?

[アップデート]

最良の解決策

タブ バーやナビゲーション バーなど、スクロールできないすべての要素のスクロールを無効にします。

anElement.addEventListener('touchmove', function( event ){ event.preventDefault() };

メイン コンテンツなどのスクロール可能な要素にスクロール ハンドラをアタッチします。

anElement.addEventListener('touchstart', function( event ){
        if( this.scrollTop === 0 ) {
            this.scrollTop += 1;
        } else if( this.scrollTop + this.offsetHeight >= this.scrollHeight ) {
            this.scrollTop -= 1;
        }
}
4

8 に答える 8

31

最近、ラバーバンディングがエクスペリエンスを損なうSPAで同じ問題<body>に遭遇しましたが、サブエリアでスクロールする必要がありました. 方法 1 が私にとって最も効果的だったので、dSquared の提案に感謝します。.scrollこれは、クラス を持っている要素 (div だけでなく) を見つけるためにツリーをずっと検索するプロジェクトで実装した彼の提案を少し拡張したものです。

// Prevent rubber-banding of the body, but allow for scrolling elements
$('body').on('touchmove', function (e) {
    var searchTerms = '.scroll, .scroll-y, .scroll-x',
        $target = $(e.target),
        parents = $target.parents(searchTerms);

    if (parents.length || $target.hasClass(searchTerms)) {
        // ignore as we want the scroll to happen
        // (This is where we may need to check if at limit)
    } else {
        e.preventDefault();
    }
});

CSS は次のようになります。

body {
    height: 100%;
    overflow: hidden;
}
.scroll, .scroll-y, .scroll-x {
    -webkit-overflow-scrolling: touch;
}
.scroll > *, .scroll-y > *, .scroll-x > * {
    -webkit-transform : translateZ(0);
}
.scroll { overflow: auto; }
.scroll-y { overflow-y: auto; }
.scroll-x { overflow-x: auto; }

必要なライブラリは 1 つだけ (jQuery またはZepto ) で、勢いのあるネイティブ スクロールが得られ、本体にラバーバンディングはありません。また、translateZ を追加して、スクロール中に要素が消えるといういくつかの問題を修正しました。GPU を使用して要素を高速化することができます。

しかし (これは大きな問題ですが)、dSquared が指摘するように、スクロール要素が限界に達し、さらにスクロールしようとすると、ページ全体がラバーバンドになります。個人的には、これは失敗だと考えているので、引き続き取り組んでいます。OPのコードの行に沿ってチェックを追加することが答えかもしれませんが、私は試していません。

更新 (10/7/12):

多くの作業の後、次のコードが iOS6 で完全に動作するようになりました (他のコードではテストしていません)。本体にラバーバンディングがなく、スクロール領域の限界に達しても問題がなくなり、全体でネイティブのスクロール パフォーマンスが得られます。明らかに元のコードよりもはるかに多くのコードですが、これにより OP の目標に最も近い動作が得られると思います。

(function registerScrolling($) {
    var prevTouchPosition = {},
        scrollYClass = 'scroll-y',
        scrollXClass = 'scroll-x',
        searchTerms = '.' + scrollYClass + ', .' + scrollXClass;

    $('body').on('touchstart', function (e) {
        var $scroll = $(e.target).closest(searchTerms),
            targetTouch = e.originalEvent.targetTouches[0];

        // Store previous touch position if within a scroll element
        prevTouchPosition = $scroll.length ? { x: targetTouch.pageX, y: targetTouch.pageY } : {};
    });

$('body').on('touchmove', function (e) {
    var $scroll = $(e.target).closest(searchTerms),
        targetTouch = e.originalEvent.targetTouches[0];

    if (prevTouchPosition && $scroll.length) {
        // Set move helper and update previous touch position
        var move = {
            x: targetTouch.pageX - prevTouchPosition.x,
            y: targetTouch.pageY - prevTouchPosition.y
        };
        prevTouchPosition = { x: targetTouch.pageX, y: targetTouch.pageY };

        // Check for scroll-y or scroll-x classes
        if ($scroll.hasClass(scrollYClass)) {
            var scrollHeight = $scroll[0].scrollHeight,
                outerHeight = $scroll.outerHeight(),

                atUpperLimit = ($scroll.scrollTop() === 0),
                atLowerLimit = (scrollHeight - $scroll.scrollTop() === outerHeight);

            if (scrollHeight > outerHeight) {
                // If at either limit move 1px away to allow normal scroll behavior on future moves,
                // but stop propagation on this move to remove limit behavior bubbling up to body
                if (move.y > 0 && atUpperLimit) {
                    $scroll.scrollTop(1);
                    e.stopPropagation();
                } else if (move.y < 0 && atLowerLimit) {
                    $scroll.scrollTop($scroll.scrollTop() - 1);
                    e.stopPropagation();
                }

                // If only moving right or left, prevent bad scroll.
                if(Math.abs(move.x) > 0 && Math.abs(move.y) < 3){
                  e.preventDefault()
                }

                // Normal scrolling behavior passes through
            } else {
                // No scrolling / adjustment when there is nothing to scroll
                e.preventDefault();
            }
        } else if ($scroll.hasClass(scrollXClass)) {
            var scrollWidth = $scroll[0].scrollWidth,
                outerWidth = $scroll.outerWidth(),

                atLeftLimit = $scroll.scrollLeft() === 0,
                atRightLimit = scrollWidth - $scroll.scrollLeft() === outerWidth;

            if (scrollWidth > outerWidth) {
                if (move.x > 0 && atLeftLimit) {
                    $scroll.scrollLeft(1);
                    e.stopPropagation();
                } else if (move.x < 0 && atRightLimit) {
                    $scroll.scrollLeft($scroll.scrollLeft() - 1);
                    e.stopPropagation();
                }
                // If only moving up or down, prevent bad scroll.
                if(Math.abs(move.y) > 0 && Math.abs(move.x) < 3){
                  e.preventDefault();
                }

                // Normal scrolling behavior passes through
            } else {
                // No scrolling / adjustment when there is nothing to scroll
                e.preventDefault();
            }
        }
    } else {
        // Prevent scrolling on non-scrolling elements
        e.preventDefault();
    }
});
})(jQuery);
于 2012-10-07T02:24:09.847 に答える
8

残念ながら、Mobile Safari のラバーバンド スクロールはブラウザ自体の組み込みの「機能」であるため、これに対する「特効薬」の修正はありません。ブラウザが提供するデフォルトのスクロール メカニズムを使用すると、ある程度のラバーバンド スクロールになります。

これに対処するには、次の 2 つの方法をお勧めします。

方法 1

touchmove要素のイベントにバインドし、イベント</body>のターゲットをチェックして、touchmove発生させたいかどうかを確認します。

HTML

<div class="scroll">
    <p>...</p>
    <p>...</p>
</div>

JS

$('body').on('touchmove', function(e) {
    // this is the node the touchmove event fired on
    // in this example it would be the </p> element
    target = e.target;

    // we need to find the parent container
    // we get it like so; assumes div as parent
    parent = $(e.target).closest('div');

    // check if the parent is a scroll window by class //
    if ($(parent).hasClass('scroll')){
        // ignore as we want the scroll to happen
    } else {
        e.preventDefault();
    }
});

JSFiddle の例はこちら

この方法ではブラウザのデフォルトのスクロールが使用されますが、スクロールの上部または下部にあるときにまだラバーバンド スクロールが発生するという欠点があります</div>

方法 2

前と同じように要素のtouchmoveイベントにバインドしますが、この場合はすべてのイベントを防止し、優れたiScroll 4プラグインを使用してスクロールを処理します。</body> touchmove

HTML

<div id="wrapper">
    <div id="scroller">
        <p>...</p>
        <p>...</p>
    </div>
</div>

JS

$(document).ready(function(){
    // prevent all scroll //
    $('body').on('touchmove', function(e) {
        e.preventDefault();
    });

    // apply iscroll to scrolling element
    // requires use of id
    var newscroll = new iScroll('wrapper');
});​​

JSFiddle の例はこちら

これは、すべてのラバーバンド スクロールをブロックし、適切なスクロール領域を提供するので、私の好みの方法ですが、プラグインの使用に依存しています。

これが役立つことを願っています

于 2012-09-27T20:46:33.913 に答える
2

jQuery と Hammer.js (jquery-implementation) を使用するソリューションを次に示します。これは 2 つのライブラリですが、モバイルで作業している場合は、とにかく Hammer を含めたいと思うでしょう。

上部にバブリングするすべてのドラッグ イベント (非スクロールのドラッグ インタラクションが stopPropagation を使用できるようにするため) について、ハンドラーは class=scrolling の要素をバブリングしたかどうかを確認します。 scrollContainer でのみ、ネイティブ スクロールが許可されます。

$("body").hammer().on('drag swipe', function(e){

    var scrollTarget = $(e.gesture.target).closest(".scrollable");
    if(scrollTarget.length)
    {
        var scrollTopMax = scrollTarget[0].scrollHeight - scrollTarget.outerHeight();
        if(scrollTopMax > 0){
            var scrollTop = scrollTarget.scrollTop();
            if(scrollTop > 0 && scrollTop < scrollTopMax){
                //console.log("scrolling in the middle");
            }
            else if(scrollTop <= 0 && e.gesture.deltaY < 0){
                //console.log("scrolling from top");
            }
            else if(scrollTop >= scrollTopMax && e.gesture.deltaY > 0){
                //console.log("scrolling from bottom");
            }
            else{
                //console.log("trying to scroll out of boundaries");
                e.gesture.preventDefault();
            }
        }
        else{
            //console.log("content to short to scroll");
            e.gesture.preventDefault();
        }
    }
    else{
        //console.log("no containing element with class=scrollable");
        e.gesture.preventDefault();
    }
});

ピンチなどでドラッグを殺すには; ビューがユーザーによるスケーリングが可能な場合、必要に応じてエスケープしてズームできるようにする

$("body").hammer().on('doubletap rotate pinch', function(e){
    e.gesture.preventDefault();
});

ios7/safari、android4.3/webview、android4.3/firefoxMobile25 でテストされ、壊れなかった唯一のソリューションです。

于 2013-11-27T18:18:56.413 に答える
1

最後に、いくつかの方法を混ぜ合わせました。これらのコードは動作中のバージョンです。ただし、 hammer.jsを含める必要があります。

CSS

.scrollable{
    overflow:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;
    *{-webkit-transform:translate3d(0,0,0);}
}

ジャバスクリプト

$(document).on("touchmove",function(e){
    e.preventDefault();
});
$("body").on("touchstart",".scrollable",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;
    }
});
$("body").on("touchmove",".scrollable",function(e){
    e.stopPropagation();
});

$("body").hammer().on("pinch",function(e){
    e.gesture.preventDefault();
});
于 2014-08-26T19:15:13.473 に答える
1

私の意見では、この問題の最善の解決策を書きました。要素に y スクロールがない限り、一般的にスクロールを無効にします。

/********************************************************************************
 * Disable rubber band (c)2013 - Mark van Wijnen | www.CrystalMinds.nl
 ********************************************************************************/
$(function(){
    var scrollY = 0;

    $(document).on('touchstart', function( e ){
        scrollY = e.originalEvent.touches.item(0).clientY;
    });

    $(document).on('touchmove', function( e ){
        var scrollPos       = e.target.scrollTop;
        var scrollDelta     = scrollY - e.originalEvent.touches.item(0).clientY;
        var scrollBottom    = scrollPos + $(e.target).height();
        scrollY             = e.originalEvent.touches.item(0).clientY;

        if ( $(e.target).css( 'overflow-y' ) != 'scroll' || ( scrollDelta < 0 && scrollPos == 0 ) || ( scrollDelta > 0 && scrollBottom == e.target.scrollHeight ) ) 
            e.preventDefault();
    });
});
于 2013-07-18T09:12:59.027 に答える