Koduję stronę, na której chcę używać tylko surowego kodu JavaScript dla interfejsu użytkownika bez żadnych ingerencji wtyczek lub frameworków.
A teraz walczę ze znalezieniem sposobu na płynne przewijanie strony bez jQuery.
javascript
html
Paolo Forgia
źródło
źródło
Odpowiedzi:
Wypróbuj to demo z płynnym przewijaniem lub algorytm, taki jak:
self.pageYOffset
element.offsetTop
window.scrollTo
Zobacz także inną popularną odpowiedź na to pytanie.
Oryginalny kod Andrew Johnsona:
function currentYPosition() { // Firefox, Chrome, Opera, Safari if (self.pageYOffset) return self.pageYOffset; // Internet Explorer 6 - standards mode if (document.documentElement && document.documentElement.scrollTop) return document.documentElement.scrollTop; // Internet Explorer 6, 7 and 8 if (document.body.scrollTop) return document.body.scrollTop; return 0; } function elmYPosition(eID) { var elm = document.getElementById(eID); var y = elm.offsetTop; var node = elm; while (node.offsetParent && node.offsetParent != document.body) { node = node.offsetParent; y += node.offsetTop; } return y; } function smoothScroll(eID) { var startY = currentYPosition(); var stopY = elmYPosition(eID); var distance = stopY > startY ? stopY - startY : startY - stopY; if (distance < 100) { scrollTo(0, stopY); return; } var speed = Math.round(distance / 100); if (speed >= 20) speed = 20; var step = Math.round(distance / 25); var leapY = stopY > startY ? startY + step : startY - step; var timer = 0; if (stopY > startY) { for ( var i=startY; i<stopY; i+=step ) { setTimeout("window.scrollTo(0, "+leapY+")", timer * speed); leapY += step; if (leapY > stopY) leapY = stopY; timer++; } return; } for ( var i=startY; i>stopY; i-=step ) { setTimeout("window.scrollTo(0, "+leapY+")", timer * speed); leapY -= step; if (leapY < stopY) leapY = stopY; timer++; } }
Powiązane linki:
źródło
Natywne płynne przewijanie w przeglądarce w JavaScript wygląda następująco:
// scroll to specific values, // same as window.scroll() method. // for scrolling a particular distance, use window.scrollBy(). window.scroll({ top: 2500, left: 0, behavior: 'smooth' }); // scroll certain amounts from current position window.scrollBy({ top: 100, // negative value acceptable left: 0, behavior: 'smooth' }); // scroll to a certain element document.querySelector('.hello').scrollIntoView({ behavior: 'smooth' });
źródło
speed
opcji. Bieżąca prędkość przewijania jest zbyt niska dla przepływu.edycja: ta odpowiedź została napisana w 2013 roku. Sprawdź poniższy komentarz Cristiana Traìny na temat requestAnimationFrame
Ja to zrobiłem. Poniższy kod nie zależy od żadnej platformy.
Ograniczenie: aktywna kotwica nie jest zapisana w adresie URL.
Wersja kodu: 1.0 | Github: https://github.com/Yappli/smooth-scroll
(function() // Code in a function to create an isolate scope { var speed = 500; var moving_frequency = 15; // Affects performance ! var links = document.getElementsByTagName('a'); var href; for(var i=0; i<links.length; i++) { href = (links[i].attributes.href === undefined) ? null : links[i].attributes.href.nodeValue.toString(); if(href !== null && href.length > 1 && href.substr(0, 1) == '#') { links[i].onclick = function() { var element; var href = this.attributes.href.nodeValue.toString(); if(element = document.getElementById(href.substr(1))) { var hop_count = speed/moving_frequency var getScrollTopDocumentAtBegin = getScrollTopDocument(); var gap = (getScrollTopElement(element) - getScrollTopDocumentAtBegin) / hop_count; for(var i = 1; i <= hop_count; i++) { (function() { var hop_top_position = gap*i; setTimeout(function(){ window.scrollTo(0, hop_top_position + getScrollTopDocumentAtBegin); }, moving_frequency*i); })(); } } return false; }; } } var getScrollTopElement = function (e) { var top = 0; while (e.offsetParent != undefined && e.offsetParent != null) { top += e.offsetTop + (e.clientTop != null ? e.clientTop : 0); e = e.offsetParent; } return top; }; var getScrollTopDocument = function() { return document.documentElement.scrollTop + document.body.scrollTop; }; })();
źródło
var _updateURL = function ( anchor, url ) { if ( (url === true || url === 'true') && history.pushState ) { history.pushState( {pos:anchor.id}, '', anchor ); } };
( przez Smooth Scroll js Chrisa Fernandi ), aby zapisać kotwicę do adresu URL. Miło widzieć, że ludzie robią to, a nie tylko „używają JQuery”! Dla przypomnienia,:target
selektory są również zgrabnym rozwiązaniem.Algorytm
Przewijanie elementu wymaga zmiany jego
scrollTop
wartości w czasie. Oblicz nowąscrollTop
wartość dla danego punktu w czasie . Aby animować płynnie, interpoluj za pomocą algorytmu płynnego kroku .Oblicz
scrollTop
w następujący sposób:var point = smooth_step(start_time, end_time, now); var scrollTop = Math.round(start_top + (distance * point));
Gdzie:
start_time
to czas rozpoczęcia animacji;end_time
kiedy animacja się zakończy(start_time + duration)
;start_top
jestscrollTop
wartością na początku; idistance
jest różnicą między żądaną wartością końcową a wartością początkową(target - start_top)
.Solidne rozwiązanie powinno wykrywać przerwanie animacji i nie tylko. Przeczytaj mój post o płynnym przewijaniu bez jQuery, aby uzyskać szczegółowe informacje.
Próbny
Zobacz JSFiddle .
Realizacja
Kod:
/** Smoothly scroll element to the given target (element.scrollTop) for the given duration Returns a promise that's fulfilled when done, or rejected if interrupted */ var smooth_scroll_to = function(element, target, duration) { target = Math.round(target); duration = Math.round(duration); if (duration < 0) { return Promise.reject("bad duration"); } if (duration === 0) { element.scrollTop = target; return Promise.resolve(); } var start_time = Date.now(); var end_time = start_time + duration; var start_top = element.scrollTop; var distance = target - start_top; // based on http://en.wikipedia.org/wiki/Smoothstep var smooth_step = function(start, end, point) { if(point <= start) { return 0; } if(point >= end) { return 1; } var x = (point - start) / (end - start); // interpolation return x*x*(3 - 2*x); } return new Promise(function(resolve, reject) { // This is to keep track of where the element's scrollTop is // supposed to be, based on what we're doing var previous_top = element.scrollTop; // This is like a think function from a game loop var scroll_frame = function() { if(element.scrollTop != previous_top) { reject("interrupted"); return; } // set the scrollTop for this frame var now = Date.now(); var point = smooth_step(start_time, end_time, now); var frameTop = Math.round(start_top + (distance * point)); element.scrollTop = frameTop; // check if we're done! if(now >= end_time) { resolve(); return; } // If we were supposed to scroll but didn't, then we // probably hit the limit, so consider it done; not // interrupted. if(element.scrollTop === previous_top && element.scrollTop !== frameTop) { resolve(); return; } previous_top = element.scrollTop; // schedule next frame for execution setTimeout(scroll_frame, 0); } // boostrap the animation process setTimeout(scroll_frame, 0); }); }
źródło
pageYOffset
iscrollTo()
naelement
zamiastscrollTop
.Zrobiłem przykład bez jQuery tutaj: http://codepen.io/sorinnn/pen/ovzdq
/** by Nemes Ioan Sorin - not an jQuery big fan therefore this script is for those who love the old clean coding style @id = the id of the element who need to bring into view Note : this demo scrolls about 12.700 pixels from Link1 to Link3 */ (function() { window.setTimeout = window.setTimeout; // })(); var smoothScr = { iterr : 30, // set timeout miliseconds ..decreased with 1ms for each iteration tm : null, //timeout local variable stopShow: function() { clearTimeout(this.tm); // stopp the timeout this.iterr = 30; // reset milisec iterator to original value }, getRealTop : function (el) // helper function instead of jQuery { var elm = el; var realTop = 0; do { realTop += elm.offsetTop; elm = elm.offsetParent; } while(elm); return realTop; }, getPageScroll : function() // helper function instead of jQuery { var pgYoff = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop; return pgYoff; }, anim : function (id) // the main func { this.stopShow(); // for click on another button or link var eOff, pOff, tOff, scrVal, pos, dir, step; eOff = document.getElementById(id).offsetTop; // element offsetTop tOff = this.getRealTop(document.getElementById(id).parentNode); // terminus point pOff = this.getPageScroll(); // page offsetTop if (pOff === null || isNaN(pOff) || pOff === 'undefined') pOff = 0; scrVal = eOff - pOff; // actual scroll value; if (scrVal > tOff) { pos = (eOff - tOff - pOff); dir = 1; } if (scrVal < tOff) { pos = (pOff + tOff) - eOff; dir = -1; } if(scrVal !== tOff) { step = ~~((pos / 4) +1) * dir; if(this.iterr > 1) this.iterr -= 1; else this.itter = 0; // decrease the timeout timer value but not below 0 window.scrollBy(0, step); this.tm = window.setTimeout(function() { smoothScr.anim(id); }, this.iterr); } if(scrVal === tOff) { this.stopShow(); // reset function values return; } } }
źródło
window.setTimeout = window.setTimeout;
Nowoczesne przeglądarki obsługują właściwość CSS „scroll-zachowanie: płynne”. Więc nawet nie potrzebujemy do tego żadnego Javascript. Po prostu dodaj to do elementu body i użyj zwykłych kotwic i linków. Dokumentacja MDN z zachowaniem przewijania
źródło
Niedawno postanowiłem rozwiązać ten problem w sytuacji, gdy jQuery nie wchodziło w grę, więc loguję tutaj moje rozwiązanie tylko dla potomności.
var scroll = (function() { var elementPosition = function(a) { return function() { return a.getBoundingClientRect().top; }; }; var scrolling = function( elementID ) { var el = document.getElementById( elementID ), elPos = elementPosition( el ), duration = 400, increment = Math.round( Math.abs( elPos() )/40 ), time = Math.round( duration/increment ), prev = 0, E; function scroller() { E = elPos(); if (E === prev) { return; } else { prev = E; } increment = (E > -20 && E < 20) ? ((E > - 5 && E < 5) ? 1 : 5) : increment; if (E > 1 || E < -1) { if (E < 0) { window.scrollBy( 0,-increment ); } else { window.scrollBy( 0,increment ); } setTimeout(scroller, time); } else { el.scrollTo( 0,0 ); } } scroller(); }; return { To: scrolling } })(); /* usage */ scroll.To('elementID');
scroll()
Funkcja używa ujawniających modułu Wzorzec przekazać identyfikator docelowy element do jejscrolling()
funkcji, za pośrednictwemscroll.To('id')
, którego ustawia wartości wykorzystywane przezscroller()
funkcję.Awaria
W
scrolling()
:el
: docelowy obiekt DOMelPos
: zwraca funkcję, poprzezelememtPosition()
którą podaje pozycję elementu docelowego względem początku strony za każdym razem, gdy jest on wywoływany.duration
: czas przejścia w milisekundach.increment
: dzieli pozycję początkową elementu docelowego na 40 kroków.time
: ustawia czas każdego kroku.prev
: poprzednia pozycja elementu docelowego wscroller()
.E
: utrzymuje pozycję elementu docelowego wscroller()
.Właściwa praca jest wykonywana przez
scroller()
funkcję, która kontynuuje wywoływanie siebie (przezsetTimeout()
), dopóki element docelowy nie znajdzie się na górze strony lub strona nie może się już przewijać.Za każdym razem, gdy
scroller()
jest wywoływana, sprawdza aktualną pozycję elementu docelowego (trzymanego w zmiennejE
) i jeśli jest to> 1
OR< -1
i jeśli strona jest nadal przewijalna, przesuwa okno oincrement
piksele - w górę lub w dół w zależności od tego, czyE
jest to wartość dodatnia czy ujemna. JeśliE
nie ma> 1
OR< -1
lubE
===,prev
funkcja zatrzymuje się. Dodałem tęDOMElement.scrollTo()
metodę po zakończeniu, aby upewnić się, że element docelowy uderzył w górę okna (nie żebyś zauważył, że jest wychylony o ułamek piksela!).if
Oświadczenie na linii 2scroller()
sprawdza, czy strona jest przewijanie (w przypadkach, w których cel może być w kierunku dolnej części strony, a strona nie może przejść dalej) za sprawdzenieE
przeciwko swojej poprzedniej pozycji (prev
).Warunek trójskładnikowy poniżej tego zmniejsza
increment
wartośćE
zbliżając się do zera. Dzięki temu strona nie przeskakuje w jedną stronę, a następnie odbija się z powrotem i przeskakuje w drugą stronę, a następnie odbija się, by ponownie prześcignąć drugą stronę, w stylu ping-ponga, do nieskończoności i dalej.Jeśli Twoja strona ma wysokość ponad 4000 pikseli, możesz chcieć zwiększyć wartości w pierwszym warunku wyrażenia trójskładnikowego (tutaj +/- 20) i / lub dzielnik, który ustawia
increment
wartość (tutaj 40).Zabawa z
duration
dzielnikiem, który ustawiaincrement
i wartościami w warunku trójskładnikowym,scroller()
powinno pozwolić na dostosowanie funkcji do strony.JSFiddle
NB Przetestowano w aktualnych wersjach przeglądarek Firefox i Chrome na Lubuntu oraz Firefox, Chrome i IE na Windows8.
źródło
Możesz także użyć właściwości zachowania przewijania . na przykład dodaj poniższą linię do swojego css
html{ scroll-behavior:smooth; }
a to spowoduje natywną funkcję płynnego przewijania. Przeczytaj więcej o zachowaniu przewijania
źródło
Zrobiłem coś takiego. Nie mam pojęcia, czy działa w IE8. Przetestowano w IE9, Mozilla, Chrome, Edge.
function scroll(toElement, speed) { var windowObject = window; var windowPos = windowObject.pageYOffset; var pointer = toElement.getAttribute('href').slice(1); var elem = document.getElementById(pointer); var elemOffset = elem.offsetTop; var counter = setInterval(function() { windowPos; if (windowPos > elemOffset) { // from bottom to top windowObject.scrollTo(0, windowPos); windowPos -= speed; if (windowPos <= elemOffset) { // scrolling until elemOffset is higher than scrollbar position, cancel interval and set scrollbar to element position clearInterval(counter); windowObject.scrollTo(0, elemOffset); } } else { // from top to bottom windowObject.scrollTo(0, windowPos); windowPos += speed; if (windowPos >= elemOffset) { // scroll until scrollbar is lower than element, cancel interval and set scrollbar to element position clearInterval(counter); windowObject.scrollTo(0, elemOffset); } } }, 1); } //call example var navPointer = document.getElementsByClassName('nav__anchor'); for (i = 0; i < navPointer.length; i++) { navPointer[i].addEventListener('click', function(e) { scroll(this, 18); e.preventDefault(); }); }
Opis
pointer
- pobierz element i sprawdź, czy ma atrybut „href”, jeśli tak, usuń „#”elem
- zmienna wskaźnika bez znaku „#”elemOffset
- odsunięcie elementu „przewiń do” od góry stronyźródło
Możesz użyć
document.querySelector('your-element').scrollIntoView({behavior: 'smooth'});
Jeśli chcesz przewijać u góry strony, możesz po prostu umieścić pusty element na górze i płynnie przewinąć do tego.
źródło
Możesz użyć pętli for z window.scrollTo i setTimeout, aby płynnie przewijać za pomocą zwykłego JavaScript. Aby przewinąć do elementu z moją
scrollToSmoothly
funkcją:scrollToSmoothly(elem.offsetTop)
(zakładając, żeelem
jest to element DOM). Możesz użyć tego do płynnego przewijania do dowolnej pozycji Y w dokumencie.function scrollToSmoothly(pos, time){ /*Time is only applicable for scrolling upwards*/ /*Code written by hev1*/ /*pos is the y-position to scroll to (in pixels)*/ if(isNaN(pos)){ throw "Position must be a number"; } if(pos<0){ throw "Position can not be negative"; } var currentPos = window.scrollY||window.screenTop; if(currentPos<pos){ var t = 10; for(let i = currentPos; i <= pos; i+=10){ t+=10; setTimeout(function(){ window.scrollTo(0, i); }, t/2); } } else { time = time || 2; var i = currentPos; var x; x = setInterval(function(){ window.scrollTo(0, i); i -= 10; if(i<=pos){ clearInterval(x); } }, time); } }
Próbny:
Pokaż fragment kodu
<button onClick="scrollToDiv()">Scroll To Element</button> <div style="margin: 1000px 0px; text-align: center;">Div element<p/> <button onClick="scrollToSmoothly(Number(0))">Scroll back to top</button> </div> <script> function scrollToSmoothly(pos, time){ /*Time is only applicable for scrolling upwards*/ /*Code written by hev1*/ /*pos is the y-position to scroll to (in pixels)*/ if(isNaN(pos)){ throw "Position must be a number"; } if(pos<0){ throw "Position can not be negative"; } var currentPos = window.scrollY||window.screenTop; if(currentPos<pos){ var t = 10; for(let i = currentPos; i <= pos; i+=10){ t+=10; setTimeout(function(){ window.scrollTo(0, i); }, t/2); } } else { time = time || 2; var i = currentPos; var x; x = setInterval(function(){ window.scrollTo(0, i); i -= 10; if(i<=pos){ clearInterval(x); } }, time); } } function scrollToDiv(){ var elem = document.querySelector("div"); scrollToSmoothly(elem.offsetTop); } </script>
źródło
<script> var set = 0; function animatescroll(x, y) { if (set == 0) { var val72 = 0; var val73 = 0; var setin = 0; set = 1; var interval = setInterval(function() { if (setin == 0) { val72++; val73 += x / 1000; if (val72 == 1000) { val73 = 0; interval = clearInterval(interval); } document.getElementById(y).scrollTop = val73; } }, 1); } } </script>
x = scrollTop
y = id elementu div używanego do przewijania
Uwaga: Aby przewinąć treść, nadaj jej identyfikator.
źródło
Oto moje rozwiązanie. Działa w większości przeglądarek
document.getElementById("scrollHere").scrollIntoView({behavior: "smooth"});
Dokumenty
document.getElementById("end").scrollIntoView({behavior: "smooth"});
body {margin: 0px; display: block; height: 100%; background-image: linear-gradient(red, yellow);} .start {display: block; margin: 100px 10px 1000px 0px;} .end {display: block; margin: 0px 0px 100px 0px;}
<div class="start">Start</div> <div class="end" id="end">End</div>
źródło
Przy użyciu następującego płynnego przewijania działa dobrze:
źródło
Oto kod, który zadziałał dla mnie.
`$('a[href*="#"]') .not('[href="#"]') .not('[href="#0"]') .click(function(event) { if ( location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname ) { var target = $(this.hash); target = target.length ? target : $('[name=' + this.hash.slice(1) + ']'); if (target.length) { event.preventDefault(); $('html, body').animate({ scrollTop: target.offset().top }, 1000, function() { var $target = $(target); $target.focus(); if ($target.is(":focus")) { return false; } else { $target.attr('tabindex','-1'); $target.focus(); }; }); } } });
`
źródło