Przejrzałem i przetestowałem różne funkcje zapobiegające przewijaniu treści wewnątrz elementu div i połączyłem funkcję, która powinna działać.
$('.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;
});
});
- Zatrzymuje to przewijanie w miejscu, w którym chcę, aby przewijanie nadal było możliwe wewnątrz kontenera
- Nie oznacza to również dezaktywacji po opuszczeniu myszy
Jakieś pomysły lub lepsze sposoby na zrobienie tego?
jquery
mousewheel
RIK
źródło
źródło
Odpowiedzi:
Aktualizacja 2: Moje rozwiązanie polega na całkowitym wyłączeniu natywnego przewijania przeglądarki (gdy kursor znajduje się wewnątrz DIV), a następnie ręcznym przewijaniu DIV za pomocą JavaScript (poprzez ustawienie jego
.scrollTop
właściwości). Alternatywnym i lepszym podejściem IMO byłoby tylko selektywne wyłączenie przewijania przeglądarki, aby zapobiec przewijaniu strony, ale nie przewijaniu DIV. Sprawdź odpowiedź Rudiego poniżej, która demonstruje to rozwiązanie.Proszę bardzo:
$( '.scrollable' ).on( 'mousewheel DOMMouseScroll', function ( e ) { var e0 = e.originalEvent, delta = e0.wheelDelta || -e0.detail; this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30; e.preventDefault(); });
Demo na żywo: https://jsbin.com/howojuq/edit?js,output
Więc ręcznie ustawiasz pozycję przewijania, a następnie po prostu zapobiegasz domyślnemu zachowaniu (którym byłoby przewijanie DIV lub całej strony internetowej).
Aktualizacja 1: Jak zauważył Chris w komentarzach poniżej, w nowszych wersjach jQuery informacje o różnicach są zagnieżdżone w
.originalEvent
obiekcie, tj. JQuery nie uwidacznia ich już w swoim niestandardowym obiekcie Event i zamiast tego musimy je pobrać z natywnego obiektu Event .źródło
-e.detail
, przetestowano w Firefoksie (Mac, Linux), Safari (Mac) i Chromium (Linux)..detail
nie odpowiada znakowi.wheelData
(który ma Chrome / IE), więc musimy go ręcznie odwrócić. Dzięki za poprawienie mojej odpowiedzi.if( e.originalEvent ) e = e.originalEvent;
if ( $(this)[0].scrollHeight !== $(this).outerHeight() ) { //yourcode }
będzie wykonywany tylko wtedy, gdy jest pasek przewijania.Jeśli nie zależy Ci na kompatybilności ze starszymi wersjami IE (<8), możesz stworzyć niestandardową wtyczkę jQuery, a następnie wywołać ją w przepełnionym elemencie.
To rozwiązanie ma przewagę nad rozwiązaniem zaproponowanym przez Šime Vidas, ponieważ nie zastępuje zachowania przewijania - po prostu blokuje je w razie potrzeby.
$.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();
źródło
[Violation] Added non-passive event listener to a scroll-blocking 'mousewheel' event. Consider marking event handler as 'passive' to make the page more responsive.
Myślę, że czasami można anulować wydarzenie 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(); });
W programie obsługi zdarzeń musisz wiedzieć:
d = e.originalEvent.deltaY, dir = d < 0 ? 'up' : 'down'
ponieważ liczba dodatnia oznacza przewijanie w dółscrollTop
na górze,scrollHeight - scrollTop - offsetHeight
na doleJeśli jesteś
top = 0
, lubbottom = 0
,odwołać wydarzenie:
e.preventDefault()
(a może nawete.stopPropagation()
).Myślę, że lepiej nie zastępować przewijania przeglądarki. Anuluj ją tylko wtedy, gdy ma to zastosowanie.
Prawdopodobnie nie jest to doskonale przeglądarka internetowa, ale nie może być bardzo trudne. Może jednak podwójny kierunek przewijania Maca jest trudny ...
źródło
Użyj poniższej właściwości CSS
overscroll-behavior: contain;
do elementu podrzędnegoźródło
zobacz, czy to ci pomoże:
demo: jsfiddle
$('#notscroll').bind('mousewheel', function() { return false });
edytować:
Spróbuj tego:
$("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; }); } });
źródło
Mniej zmyślnym rozwiązaniem, moim zdaniem, jest ustawienie przepełnienia ukrytego na ciele po najechaniu kursorem myszy na przewijalny element div. Zapobiegnie to przewijaniu treści, ale pojawi się niepożądany efekt „skakania”. Następujące rozwiązanie pozwala to obejść:
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" }); })
W razie potrzeby możesz uczynić swój kod mądrzejszym. Na przykład możesz sprawdzić, czy treść ma już wypełnienie, a jeśli tak, dodaj do tego nową wyściółkę.
źródło
W powyższym rozwiązaniu jest mały błąd dotyczący Firefoksa. W przeglądarce Firefox zdarzenie „DOMMouseScroll” nie ma właściwości e.detail, aby uzyskać tę właściwość, należy wpisać „e.originalEvent.detail”.
Oto działające rozwiązanie dla przeglądarki 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; };
źródło
tutaj proste rozwiązanie bez jQuery, które nie niszczy natywnego przewijania przeglądarki (to jest: brak sztucznego / brzydkiego przewijania):
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(); });
Demo na żywo: http://jsfiddle.net/ibcaliax/bwmzfmq7/4/
źródło
Oto moje rozwiązanie, którego używałem w aplikacjach.
Wyłączyłem przepełnienie treści i umieściłem cały html witryny wewnątrz kontenera div. Kontenery witryny są przepełnione, dlatego użytkownik może przewijać stronę zgodnie z oczekiwaniami.
Następnie utworzyłem rodzeństwo div (#Prevent) z wyższym indeksem Z, który obejmuje całą witrynę. Ponieważ #Prevent ma wyższy indeks Z, nakłada się na kontener witryny. Kiedy #Prevent jest widoczne, mysz nie jest już najeżdżana na kontenery witryny, więc przewijanie nie jest możliwe.
Możesz oczywiście umieścić inny element div, na przykład modalny, z indeksem Z wyższym niż #Prevent w znaczniku. Pozwala to na tworzenie wyskakujących okienek, które nie cierpią z powodu problemów z przewijaniem.
To rozwiązanie jest lepsze, ponieważ nie ukrywa pasków przewijania (wpływa na przeskok). Nie wymaga detektorów zdarzeń i jest łatwy do wdrożenia. Działa we wszystkich przeglądarkach, chociaż z IE7 i 8 musisz się bawić (w zależności od konkretnego kodu).
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; } }
wyłącz / włącz przewijanie
PreventScroll('on'); // prevent scrolling PreventScroll('off'); // allow scrolling
źródło
Musiałem dodać to zdarzenie do wielu elementów, które mogą mieć pasek przewijania. W przypadkach, gdy nie było paska przewijania, główny pasek przewijania nie działał tak, jak powinien. Więc zrobiłem małą zmianę w kodzie @ Šime w następujący sposób:
$( '.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(); } });
Teraz tylko elementy z paskiem przewijania zapobiegną zatrzymaniu głównego przewijania.
źródło
Czysta wersja javascript odpowiedzi Vidasa
el$
to węzeł DOM samolotu, który przewijasz.function onlyScrollElement(event, el$) { var delta = event.wheelDelta || -event.detail; el$.scrollTop += (delta < 0 ? 1 : -1) * 10; event.preventDefault(); }
Upewnij się, że nie dołączasz nawet wielokrotnie! Oto przykład,
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);
Uwaga , funkcja tam musi być stała, jeśli za każdym razem inicjalizujesz funkcję przed jej dołączeniem, tj. nie będzie działać.
var func = function (...)
removeEventListener
źródło
Możesz to zrobić bez JavaScript. Możesz ustawić styl obu elementów div na
position: fixed
ioverflow-y: auto
. Być może trzeba będzie ustawić jeden z nich wyżej od drugiego, ustawiając jegoz-index
(jeśli nachodzą na siebie).Oto podstawowy przykład dotyczący CodePen .
źródło
Oto wtyczka, która jest przydatna do zapobiegania przewijaniu przez rodzica podczas przewijania określonego elementu div i ma wiele opcji do zabawy.
Sprawdź to tutaj:
https://github.com/MohammadYounes/jquery-scrollLock
Stosowanie
Uruchom blokadę przewijania przez JavaScript:
$('#target').scrollLock();
Uruchom blokadę przewijania za pomocą znaczników:
<!-- 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>
Zobacz demo
źródło
oferując to jako możliwe rozwiązanie, jeśli nie sądzisz, że użytkownik będzie miał negatywne doświadczenia związane z oczywistą zmianą. Po prostu zmieniłem klasę przepełnienia ciała na ukrytą, gdy mysz znajdowała się nad docelowym elementem div; potem zmieniłem element div ciała na ukryty przepełnienie, gdy mysz wychodzi.
Osobiście nie uważam, że wygląda to źle, mój kod mógłby użyć przełącznika, aby uczynić go czystszym, a są oczywiste korzyści z umożliwienia tego efektu bez świadomości użytkownika. Więc to jest prawdopodobnie ostatnia deska ratunku.
//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"; }
źródło
Wszystko czego potrzebujesz to
e.preventDefault();
na elemencie potomnym.
źródło