Я рассмотрел и протестировал различные функции, предотвращающие способность тела прокручиваться внутри 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;
});
});
- Это останавливает всю прокрутку там, где я хочу, чтобы прокрутка все еще была возможна внутри контейнера.
- Это также не деактивируется при отпускании мыши
Есть идеи или лучшие способы сделать это?
jquery
mousewheel
RIK
источник
источник
Ответы:
Обновление 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,output
Таким образом, вы вручную устанавливаете положение прокрутки, а затем просто предотвращаете поведение по умолчанию (которое будет заключаться в прокрутке DIV или всей веб-страницы).
Обновление 1. Как отметил Крис в комментариях ниже, в более новых версиях jQuery дельта-информация вложена в
.originalEvent
объект, т.е. jQuery больше не предоставляет ее в своем настраиваемом объекте Event, и вместо этого мы должны извлекать ее из собственного объекта Event. .источник
-e.detail
, протестировано в Firefox (Mac, Linux), Safari (Mac) и Chromium (Linux)..detail
не соответствует знаку.wheelData
(который есть в Chrome / IE), поэтому мы должны инвертировать его вручную. Спасибо, что исправили мой ответ.if( e.originalEvent ) e = e.originalEvent;
if ( $(this)[0].scrollHeight !== $(this).outerHeight() ) { //yourcode }
будет выполняться только при наличии полосы прокрутки.Если вас не волнует совместимость со старыми версиями IE (<8), вы можете создать собственный плагин jQuery, а затем вызвать его на переполняющем элементе.
Это решение имеет преимущество перед предложенным Шиме Видасом, поскольку оно не перезаписывает поведение прокрутки - оно просто блокирует его, когда это необходимо.
$.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();
источник
[Violation] Added non-passive event listener to a scroll-blocking 'mousewheel' event. Consider marking event handler as 'passive' to make the page more responsive.
Я думаю, что иногда можно отменить событие 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 непросто ...
источник
Используйте свойство ниже CSS
overscroll-behavior: contain;
для дочернего элементаисточник
посмотрим, поможет ли это вам:
демонстрация: 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" }); })
При необходимости вы можете сделать свой код умнее. Например, вы можете проверить, есть ли в теле уже заполнение, и если да, добавить к нему новое заполнение.
источник
В приведенном выше решении есть небольшая ошибка относительно 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, которое не уничтожает собственную прокрутку браузера (это: без искусственной / некрасивой прокрутки):
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/
источник
Вот мое решение, которое я использовал в приложениях.
Я отключил переполнение тела и поместил весь html веб-сайта в контейнер div. Контейнеры веб-сайта переполнены, поэтому пользователь может прокручивать страницу, как и ожидалось.
Затем я создал родственный div (#Prevent) с более высоким z-индексом, который охватывает весь веб-сайт. Поскольку #Prevent имеет более высокий z-индекс, он перекрывает контейнер веб-сайта. Когда отображается #Prevent, мышь больше не наводит курсор на контейнеры веб-сайта, поэтому прокрутка невозможна.
Вы, конечно, можете разместить в разметке другой div, например модальный, с более высоким z-index, чем #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
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 (...)
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>
Посмотреть демо
источник
просто предлагайте это как возможное решение, если вы не думаете, что у пользователя будет негативный опыт очевидного изменения. Я просто изменил класс переполнения тела на скрытый, когда указатель мыши находился над целевым div; затем я изменил div тела на скрытое переполнение, когда мышь уходит.
Лично я не думаю, что это выглядит плохо, в моем коде можно использовать переключение, чтобы сделать его чище, и есть очевидные преимущества для того, чтобы сделать этот эффект возможным без ведома пользователя. Так что это, вероятно, самый хакерский ответ.
//listen mouse on and mouse off for the button pxMenu.addEventListener("mouseover", toggleA1); pxOptContainer.addEventListener("mouseout", toggleA2); //show / hide the pixel option menu function toggleA1(){ pxOptContainer.style.display = "flex"; body.style.overflow = "hidden"; } function toggleA2(){ pxOptContainer.style.display = "none"; body.style.overflow = "hidden scroll"; }
источник
Все, что тебе нужно
e.preventDefault();
на дочернем элементе.
источник