web-dev-qa-db-ja.com

DIV要素をスクロールするときにページのスクロールを防ぐ方法は?

Div内での身体のスクロールを防ぐためのさまざまな機能を確認およびテストし、機能するはずの機能を組み合わせました。

$('.scrollable').mouseenter(function() {
    $('body').bind('mousewheel DOMMouseScroll', function() {
        return false;
    });
    $(this).bind('mousewheel DOMMouseScroll', function() {
        return true;
    });
});
$('.scrollable').mouseleave(function() {
    $('body').bind('mousewheel DOMMouseScroll', function() {
        return true;
    });
});
  • これは、スクロールをコンテナ内で引き続き可能にするために、すべてのスクロールを停止しています
  • これは、マウスを離しても無効化されません

これを行うためのアイデア、またはより良い方法はありますか?

90
Robin Knight

更新2:私の解決策は、ブラウザのネイティブスクロールを完全に無効にし(カーソルがDIV内にある場合)、JavaScriptでDIVを手動でスクロールすることです(by .scrollTopプロパティを設定します)。代替のIMOより優れたアプローチは、DIVスクロールではなく、ページスクロールを防ぐために、ブラウザーのスクロールのみを選択的に無効にすることです。このソリューションを実証するルディの以下の回答をご覧ください。


どうぞ:

$( '.scrollable' ).on( 'mousewheel DOMMouseScroll', function ( e ) {
    var e0 = e.originalEvent,
        delta = e0.wheelDelta || -e0.detail;

    this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30;
    e.preventDefault();
});

ライブデモ:https://jsbin.com/howojuq/edit?js,output

したがって、手動でスクロール位置を設定してから、デフォルトの動作(DIVまたはWebページ全体をスクロールすること)を防止するだけです。

更新1:以下のコメントでChrisが述べたように、jQueryの新しいバージョンでは、デルタ情報は.originalEventオブジェクト内にネストされています。 jQueryはカスタムイベントオブジェクトでそれを公開しなくなり、代わりにネイティブイベントオブジェクトから取得する必要があります。

162
Šime Vidas

古いIEバージョン(<8)との互換性を気にしない場合は、カスタムjQueryプラグインを作成し、オーバーフロー要素で呼び出すことができます。

このソリューションは、スクロール動作を上書きしないため、ŠimeVidasが提案したものよりも有利です。適切な場合にブロックするだけです。

$.fn.isolatedScroll = function() {
    this.bind('mousewheel DOMMouseScroll', function (e) {
        var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.detail,
            bottomOverflow = this.scrollTop + $(this).outerHeight() - this.scrollHeight >= 0,
            topOverflow = this.scrollTop <= 0;

        if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) {
            e.preventDefault();
        }
    });
    return this;
};

$('.scrollable').isolatedScroll();
29
wojcikstefan

私は時々mousescrollイベントをキャンセルすることができると思います: http://jsfiddle.net/rudiedirkx/F8qSq/show/

$elem.on('wheel', function(e) {
    var d = e.originalEvent.deltaY,
        dir = d < 0 ? 'up' : 'down',
        stop = (dir == 'up' && this.scrollTop == 0) || 
               (dir == 'down' && this.scrollTop == this.scrollHeight-this.offsetHeight);
    stop && e.preventDefault();
});

イベントハンドラー内では、次のことを知る必要があります。

  • スクロール方向
    d = e.originalEvent.deltaY, dir = d < 0 ? 'up' : 'down'正の数は下にスクロールすることを意味するため
  • スクロール位置
    scrollTop上部、scrollHeight - scrollTop - offsetHeight下部

もしあなたが〜なら

  • 上にスクロールし、top = 0、または
  • 下にスクロールし、bottom = 0

イベントをキャンセルします:e.preventDefault()(そしておそらくe.stopPropagation())。

ブラウザのスクロール動作を無効にしない方が良いと思います。該当する場合にのみキャンセルしてください。

それは完全にxbrowserではありませんが、それは非常に難しいことはできません。 Macのデュアルスクロール方向は難しいかもしれませんが...

21
Rudie

上記のソリューションには、Firefoxに関する少しの間違いがあります。 Firefoxの「DOMMouseScroll」イベントにはe.detailプロパティがありません。このプロパティを取得するには、次の「e.originalEvent.detail」を記述する必要があります。

Firefoxの実用的なソリューションは次のとおりです。

$.fn.isolatedScroll = function() {
    this.on('mousewheel DOMMouseScroll', function (e) {
        var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.originalEvent.detail,
            bottomOverflow = (this.scrollTop + $(this).outerHeight() - this.scrollHeight) >= 0,
            topOverflow = this.scrollTop <= 0;

        if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) {
            e.preventDefault();
        }
    });
    return this;
};
3
Vladimir Kuzmin

ここでは、ブラウザのネイティブスクロールを破壊しないjQueryを使用しないシンプルなソリューション(これは、人為的/ ugいスクロールがありません):

var scrollable = document.querySelector('.scrollable');

scrollable.addEventListener('wheel', function(event) {
    var deltaY = event.deltaY;
    var contentHeight = scrollable.scrollHeight;
    var visibleHeight = scrollable.offsetHeight;
    var scrollTop = scrollable.scrollTop;

    if (scrollTop === 0 && deltaY < 0)
        event.preventDefault();
    else if (visibleHeight + scrollTop === contentHeight && deltaY > 0)
        event.preventDefault();
});

ライブデモ: http://jsfiddle.net/ibcaliax/bwmzfmq7/4/

3

これがあなたを助けるかどうか見てください:

デモ: jsfiddle

$('#notscroll').bind('mousewheel', function() {
     return false
});

編集:

これを試して:

    $("body").delegate("div.scrollable","mouseover mouseout", function(e){
       if(e.type === "mouseover"){
           $('body').bind('mousewheel',function(){
               return false;
           });
       }else if(e.type === "mouseout"){
           $('body').bind('mousewheel',function(){
               return true;
           });
       }
    });
3
Ricardo Binns

私の意見では、あまりハッキーではない解決策は、スクロール可能なdivの上にマウスを置くと、オーバーフローがボディに隠されるようにすることです。これにより、ボディのスクロールが防止されますが、不要な「ジャンプ」効果が発生します。次のソリューションはそれを回避します:

jQuery(".scrollable")
    .mouseenter(function(e) {
        // get body width now
        var body_width = jQuery("body").width();
        // set overflow hidden on body. this will prevent it scrolling
        jQuery("body").css("overflow", "hidden"); 
        // get new body width. no scrollbar now, so it will be bigger
        var new_body_width = jQuery("body").width();
        // set the difference between new width and old width as padding to prevent jumps                                     
        jQuery("body").css("padding-right", (new_body_width - body_width)+"px");
    })
    .mouseleave(function(e) {
        jQuery("body").css({
            overflow: "auto",
            padding-right: "0px"
        });
    })

必要に応じて、コードをよりスマートにすることができます。たとえば、本文に既にパディングがあるかどうかをテストし、ある場合は新しいパディングを追加します。

3

これがアプリケーションで使用したソリューションです。

ボディオーバーフローを無効にし、ウェブサイトのHTML全体をコンテナdiv内に配置しました。 Webサイトのコンテナーがオーバーフローしているため、ユーザーは期待どおりにページをスクロールできます。

次に、ウェブサイト全体をカバーするより高いz-indexで兄弟div(#Prevent)を作成しました。 #Preventのz-indexが高いため、Webサイトコンテナーとオーバーラップします。 #Preventが表示されている場合、マウスはWebサイトコンテナーにホバーしていないため、スクロールはできません。

もちろん、モーダルなどの別のdivを、マークアップの#Preventよりも高いz-indexで配置することもできます。これにより、スクロールの問題のないポップアップウィンドウを作成できます。

このソリューションは、スクロールバーを非表示にしないので優れています(ジャンプ効果)。イベントリスナーは必要なく、実装も簡単です。 IE7および8では、(特定のコードに応じて)試してみる必要がありますが、すべてのブラウザーで機能します。

html

<body>
  <div id="YourModal" style="display:none;"></div>
  <div id="Prevent" style="display:none;"></div>
  <div id="WebsiteContainer">
     <div id="Website">
     website goes here...
     </div>
  </div>
</body>

cSS

body { overflow: hidden; }

#YourModal {
 z-index:200;
 /* modal styles here */
}

#Prevent {
 z-index:100;
 position:absolute;
 left:0px;
 height:100%;
 width:100%;
 background:transparent;
}

#WebsiteContainer {
  z-index:50;
  overflow:auto;
  position: absolute;
  height:100%;
  width:100%;
}
#Website {
  position:relative;
}

jquery/js

function PreventScroll(A) { 
  switch (A) {
    case 'on': $('#Prevent').show(); break;
    case 'off': $('#Prevent').hide(); break;
  }
}

スクロールを無効/有効にします

PreventScroll('on'); // prevent scrolling
PreventScroll('off'); // allow scrolling
2
David D

このイベントをスクロールバーを持つ可能性のある複数の要素に追加する必要がありました。スクロールバーが存在しない場合、メインのスクロールバーは正常に機能しませんでした。そこで、次のように@Šimeコードに小さな変更を加えました。

$( '.scrollable' ).on( 'mousewheel DOMMouseScroll', function ( e ) {
    if($(this).prop('scrollHeight') > $(this).height())
    {
        var e0 = e.originalEvent, delta = e0.wheelDelta || -e0.detail;

        this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30;
        e.preventDefault();
    }       
});

現在、スクロールバーを持つ要素のみが、メインスクロールの開始を停止します。

1
Ricky

Vidasの答えの純粋なJavaScriptバージョン、el$は、スクロールしているプレーンのDOMノードです。

function onlyScrollElement(event, el$) {
    var delta = event.wheelDelta || -event.detail;
    el$.scrollTop += (delta < 0 ? 1 : -1) * 10;
    event.preventDefault();
}

何度も添付しないでください!以下に例を示します。

var ul$ = document.getElementById('yo-list');
// IE9, Chrome, Safari, Opera
ul$.removeEventListener('mousewheel', onlyScrollElement);
ul$.addEventListener('mousewheel', onlyScrollElement);
// Firefox
ul$.removeEventListener('DOMMouseScroll', onlyScrollElement);
ul$.addEventListener('DOMMouseScroll', onlyScrollElement);

注意事項、アタッチする前に毎回関数を再初期化する場合、関数は定数である必要があります。 var func = function (...) the removeEventListenerは機能しません。

0
srcspider

JavaScriptなしでこれを行うことができます。両方のdivでスタイルをposition: fixedおよびoverflow-y: autoに設定できます。 z-index(重複する場合)を設定して、一方を他方よりも高くする必要がある場合があります。

CodePenの基本的な例 です。

0
Carl Smith

特定のdivのスクロール中に親のスクロールを防ぐのに役立つプラグインを次に示します。また、さまざまなオプションがあります。

こちらをご覧ください:

https://github.com/MohammadYounes/jquery-scrollLock

使用法

JavaScriptを介したスクロールロックのトリガー:

$('#target').scrollLock();

マークアップによるスクロールロックのトリガー:

    <!-- HTML -->
<div data-scrollLock
     data-strict='true'
     data-selector='.child'
     data-animation='{"top":"top locked","bottom":"bottom locked"}'
     data-keyboard='{"tabindex":0}'
     data-unblock='.inner'>
     ...
</div>

<!-- JavaScript -->
<script type="text/javascript">
  $('[data-scrollLock]').scrollLock()
</script>

表示 デモ

0
MR_AMDEV