Как предотвратить прокрутку страницы при прокрутке элемента 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;
});
});
- это останавливает всю прокрутку, где, как я хочу, прокрутка все еще возможна внутри контейнера
- Это также не отключается на мыши оставить
есть идеи, или лучшие способы сделать это?
12 ответов:
обновление 2: мое решение основано на отключении собственной прокрутки браузера в целом (когда курсор находится внутри DIV), а затем вручную прокручивает DIV с помощью JavaScript (установив его
.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, выход
таким образом, вы вручную устанавливаете положение прокрутки, а затем просто предотвращаете поведение по умолчанию (которое будет прокручивать DIV или всю веб-страницу).
обновление 1: как отметил Крис в комментариях ниже, в более новых версиях jQuery Дельта-информация вложена в
.originalEvent
объект, т. е. jQuery не предоставляет его в своем пользовательском объекте события больше, и мы должны получить его из собственного объекта события вместо этого.
Если вы не заботитесь о совместимости со старыми версиями IE (
Это решение имеет преимущество перед предложенным Шиме Видасом, поскольку оно не перезаписывает поведение прокрутки - оно просто блокирует его, когда это необходимо.
$.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 является сложным, хотя...
посмотреть, если это поможет вам:
демо: jsfiddle
$('#notscroll').bind('mousewheel', function() { return false });
edit:
попробуйте это:
$("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" }); })
вы можете сделать свой код умнее, если это необходимо. Например, вы можете проверить, есть ли в теле уже заполнение, и если да, добавьте к нему новое заполнение.
в решении выше есть небольшая ошибка в отношении Firefox. В Firefox событие "DOMMouseScroll" не имеет свойства e.detail,чтобы получить это свойство, вы должны написать следующее 'E.originalEvent.подробно".
вот рабочее решение для 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, которое не уничтожает собственную прокрутку браузера (это: нет искусственной / уродливой прокрутки):
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(); });
вот мое решение, которое я использовал в приложениях.
Я отключил переполнение тела и разместил весь сайт HTML внутри div-контейнера по. На сайте контейнеры переполняются и поэтому пользователь может прокручивать страницы, как ожидалось.
затем я создал брат div (#Prevent) с более высоким Z-индексом, который охватывает весь веб-сайт. Поскольку #Prevent имеет более высокий Z-индекс, он перекрывает контейнер веб-сайта. Когда #Prevent отображается, мышь больше не парит контейнеры веб-сайта, поэтому прокрутка невозможна.
вы можете, конечно, разместить другой div, такой как ваш модальный, с более высоким Z-индексом, чем #Prevent в разметке. Это позволяет создавать всплывающие окна, которые не страдают от проблем скроллинга.
это решение лучше, потому что оно не скрывает полосы прокрутки (эффект прыжка). Это не требует прослушивателей событий, и это легко реализовать. Он работает во всех браузерах, хотя с 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(); } });
теперь только элементы с полосой прокрутки будут препятствовать остановке основной прокрутки.
чистая версия javascript ответа Vidas,
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 (...)
theremoveEventListener
не будет работать.
вы можете сделать это без JavaScript. Вы можете установить стиль на обоих дивах в
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>
посмотреть демо