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;
});
});
これを行うためのアイデア、またはより良い方法はありますか?
更新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はカスタムイベントオブジェクトでそれを公開しなくなり、代わりにネイティブイベントオブジェクトから取得する必要があります。
古い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();
私は時々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のデュアルスクロール方向は難しいかもしれませんが...
上記のソリューションには、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;
};
ここでは、ブラウザのネイティブスクロールを破壊しない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();
});
これがあなたを助けるかどうか見てください:
デモ: 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;
});
}
});
私の意見では、あまりハッキーではない解決策は、スクロール可能な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"
});
})
必要に応じて、コードをよりスマートにすることができます。たとえば、本文に既にパディングがあるかどうかをテストし、ある場合は新しいパディングを追加します。
これがアプリケーションで使用したソリューションです。
ボディオーバーフローを無効にし、ウェブサイトの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
このイベントをスクロールバーを持つ可能性のある複数の要素に追加する必要がありました。スクロールバーが存在しない場合、メインのスクロールバーは正常に機能しませんでした。そこで、次のように@Š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();
}
});
現在、スクロールバーを持つ要素のみが、メインスクロールの開始を停止します。
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
は機能しません。
JavaScriptなしでこれを行うことができます。両方のdivでスタイルをposition: fixed
およびoverflow-y: auto
に設定できます。 z-index
(重複する場合)を設定して、一方を他方よりも高くする必要がある場合があります。
CodePenの基本的な例 です。
特定の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>
表示 デモ