2017-07-23 50 views
10

Chcę, aby strona przewijała się powoli i płynnie. Cóż, prędkość powinna być regulowana. Użytkownik powinien również mieć możliwość przewijania w górę, gdy skrypt przewija się w dół. Najpierw próbowałem tego:Powoli przewijaj stronę w dół na stałe, bez dużego obciążenia procesora lub przewijania z opóźnieniem.

var autoScrollDelay = 1 
var autoScrollSpeed = 1 
var autoScrollTimer 
function setAutoScroll(newValue) { 
    autoScrollSpeed = newValue ? newValue : autoScrollSpeed 
    if (autoScrollTimer) { 
     clearInterval(autoScrollTimer) 
    } 
    if (autoScrollDelay) { 
     autoScrollTimer = setInterval(function(){ 
      window.scrollBy(0,autoScrollSpeed) 
     },autoScrollDelay) 
    } 
} 
setAutoScroll(1) // higher number = faster scrolling 

Ale to było przyczyną bardzo dużego obciążenia procesora, a najwolniejsza prędkość była zbyt szybka. Poza tym ręczne przewijanie nie działało poprawnie podczas działania kodu.

Potem próbowałem:

var autoScrollDelay = 1 
var autoScrollSpeed = 1 
var autoScrollTimer 
function setAutoScroll(newValue) { 
    autoScrollDelay = newValue ? newValue : autoScrollDelay //using autoScrollDelay instead of autoScrollSpeed 
    if (autoScrollTimer) { 
     clearInterval(autoScrollTimer) 
    } 
    if (autoScrollDelay) { 
     autoScrollTimer = setInterval(function(){ 
      window.scrollBy(0,autoScrollSpeed) 
     },autoScrollDelay) 
    } 
} 
setAutoScroll(200) // higher number scrolls slower 

Ale nie było sprawne przewijanie podczas ustawiania go zbyt wolno (na przykład 200).

Potem próbowałem:

$("html, body").animate({ 
    scrollTop: $('html, body').get(0).scrollHeight, 
}, 40000, "linear"); 

Ale znowu obciążenie CPU było zbyt wysokie i przewijanie w górę lub w dół ręcznie nie można było w ten sposób.

Czy jest lepszy sposób to zrobić?

+0

CSS translateY może być najlepszym rozwiązaniem. –

+0

Czy możesz utworzyć link do swojej strony? Jaka jest waga strony - czy masz dużo ciężkich obrazów lub animacji lub cokolwiek się dzieje, gdy strona przewija się? –

+0

Nie ma znaczenia, na której stronie uruchomiłem kod. Możesz wypróbować to tutaj na Stackoverflow. Mój Firefox pokazuje 10-12% obciążenia procesora, prawdopodobnie tyle samo, co skrypt z pojedynczym gwintem, który może obsłużyć procesor 8 wątków. – Forivin

Odpowiedz

9

Oto jedna z możliwych realizacji. Częstotliwość odświeżania jest stała i odpowiada fps w poniższym kodzie. Aby upewnić się, że prędkość jest stała, biorę pod uwagę czas, jaki upłynął od poprzedniego przewijania podczas obliczania nowej pozycji przewijania. Ręczne przewijanie jest dozwolone (z paskiem przewijania, kółkiem myszy lub dotknięciem na urządzeniach mobilnych) i brane pod uwagę poprzez przetwarzanie zdarzeń scroll, i touchmove. Możesz zobaczyć kod w pracy pod numerem this codepen.

var fps = 100; 
var speedFactor = 0.001; 
var minDelta = 0.5; 
var autoScrollSpeed = 10; 
var autoScrollTimer, restartTimer; 
var isScrolling = false; 
var prevPos = 0, currentPos = 0; 
var currentTime, prevTime, timeDiff; 

window.addEventListener("scroll", function (e) { 
    // window.pageYOffset is the fallback value for IE 
    currentPos = window.scrollY || window.pageYOffset; 
}); 

window.addEventListener("wheel", handleManualScroll); 
window.addEventListener("touchmove", handleManualScroll); 

function handleManualScroll() { 
    // window.pageYOffset is the fallback value for IE 
    currentPos = window.scrollY || window.pageYOffset; 
    clearInterval(autoScrollTimer); 
    if (restartTimer) { 
     clearTimeout(restartTimer); 
    } 
    restartTimer = setTimeout(() => { 
     prevTime = null; 
     setAutoScroll(); 
    }, 50); 
} 

function setAutoScroll(newValue) { 
    if (newValue) { 
     autoScrollSpeed = speedFactor * newValue; 
    } 
    if (autoScrollTimer) { 
     clearInterval(autoScrollTimer); 
    } 
    autoScrollTimer = setInterval(function(){ 
     currentTime = Date.now(); 
     if (prevTime) { 
      if (!isScrolling) { 
       timeDiff = currentTime - prevTime; 
       currentPos += autoScrollSpeed * timeDiff; 
       if (Math.abs(currentPos - prevPos) >= minDelta) { 
        isScrolling = true; 
        window.scrollTo(0, currentPos); 
        isScrolling = false; 
        prevPos = currentPos; 
        prevTime = currentTime; 
       } 
      } 
     } else { 
      prevTime = currentTime; 
     } 
    }, 1000/fps); 
} 

setAutoScroll(20); 
+0

Czy istnieje sposób, aby umożliwić przewijanie ręczne, gdy jest on uruchomiony? – Forivin

+0

@Forivin - Dzięki bieżącemu kodowi mogę przewijać ręcznie podczas automatycznego przewijania (testowane za pomocą [codepen] (https://codepen.io/ConnorsFan/pen/yoOzGx) w Chrome, FF i IE). Nie możesz? – ConnorsFan

+0

Niezupełnie. Czuje się bardzo niereagujący. Nawet jeśli próbuję ręcznie przewijać w górę lub w dół tak szybko, jak tylko mogę, ledwo widzę reakcję. To tak, jakby ręczna odległość przewijania ustawiona była na 1 piksel i działa tylko co 2 sekundy. Testowane w chromie i firefoxie (z włączonym płynnym przewijaniem). Jeśli wyłączę płynne przewijanie w firefoxie, to faktycznie działa dobrze. Ale potrzebuję rozwiązania, które działa w obu trybach. – Forivin

3

Funkcja od this article wykorzystuje waniliowy JS do wykonywania płynnego przewijania z różnymi prędkościami. Oto demo:

document.getElementById("scrollBottomButton").onclick = function() { 
 
    var duration = document.getElementById("bottomScrollDuration").value * 1000; 
 
    scrollIt(document.querySelector("#bottom-row"), duration, "easeOutQuad"); 
 
}; 
 

 
document.getElementById("scrollTopButton").onclick = function() { 
 
    var duration = document.getElementById("topScrollDuration").value * 1000; 
 
    scrollIt(document.getElementById("top-row"), duration, "easeOutQuad"); 
 
}; 
 

 
// thanks to https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/ 
 
function scrollIt(destination, duration = 200, easing = "linear", callback) { 
 
    const easings = { 
 
    linear(t) { 
 
     return t; 
 
    }, 
 
    easeOutQuad(t) { 
 
     return t * (2 - t); 
 
    } 
 
    }; 
 

 
    const start = window.pageYOffset; 
 
    const startTime = "now" in window.performance 
 
    ? performance.now() 
 
    : new Date().getTime(); 
 

 
    const documentHeight = Math.max(
 
    document.body.scrollHeight, 
 
    document.body.offsetHeight, 
 
    document.documentElement.clientHeight, 
 
    document.documentElement.scrollHeight, 
 
    document.documentElement.offsetHeight 
 
); 
 
    const windowHeight = 
 
     window.innerHeight || 
 
     document.documentElement.clientHeight || 
 
     document.getElementsByTagName("body")[0].clientHeight; 
 
    const destinationOffset = typeof destination === "number" 
 
    ? destination 
 
    : destination.offsetTop; 
 
    const destinationOffsetToScroll = Math.round(
 
    documentHeight - destinationOffset < windowHeight 
 
    ? documentHeight - windowHeight 
 
    : destinationOffset 
 
); 
 

 
    if ("requestAnimationFrame" in window === false) { 
 
    window.scroll(0, destinationOffsetToScroll); 
 
    if (callback) { 
 
     callback(); 
 
    } 
 
    return; 
 
    } 
 

 
    function scroll() { 
 
    const now = "now" in window.performance 
 
    ? performance.now() 
 
    : new Date().getTime(); 
 
    const time = Math.min(1, (now - startTime)/duration); 
 
    const timeFunction = easings[easing](time); 
 
    window.scroll(
 
     0, 
 
     Math.ceil(timeFunction * (destinationOffsetToScroll - start) + start) 
 
    ); 
 

 
    if (window.pageYOffset === destinationOffsetToScroll) { 
 
     if (callback) { 
 
     callback(); 
 
     } 
 
     return; 
 
    } 
 

 
    requestAnimationFrame(scroll); 
 
    } 
 

 
    scroll(); 
 
} 
 

 

 
// scroll testing  
 
var middleHtml = []; 
 

 
const schiller = "Nur Beharrung führt zum Ziel, Nur die Fülle führt zur Klarheit, Und im Abgrund wohnt die Wahrheit.".split(' ') 
 

 
for(var i=0; i<schiller.length;i+=1){ 
 
    middleHtml.push("<div class=' container row' id='scrolling'><h1 style='margin: 30rem 10rem 30rem 0;font-size: 3.5em;font-family: Helvetica, sans-serif;color: #fff;'>"+schiller[i]+"</h1></div>"); 
 
} 
 

 

 
document.getElementById('middle').innerHTML = middleHtml.join('');
.container-fluid { 
 
background: #e52d27; 
 
background: -webkit-linear-gradient(to top, #b31217, #e52d27); 
 
background: linear-gradient(to top, #b31217, #e52d27); 
 
} 
 

 
.container-fluid input, .container-fluid .btn { 
 
    border-radius: 0; 
 
} 
 

 
.btn { 
 
    background: rgba(210,200,200,0.95); 
 
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/> 
 

 
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/> 
 

 
<div class='container-fluid'> 
 
    <div class='row' id='top-row'> 
 
    <div class='col-sm-8'> 
 
     <input class='form-control' id='bottomScrollDuration' placeholder='Enter duration in seconds (4, 25, 40, etc...)' /> 
 
    </div> 
 
    <div class='col-sm-4'> 
 
     <button class='btn' id='scrollBottomButton'>Scroll to bottom</button> 
 
    </div>  
 
    </div> 
 
    <div id='middle'>  
 
    </div> 
 

 
    <div class='row' id='bottom-row'> 
 
    <div class='col-sm-8'> 
 
     <input class='form-control' id='topScrollDuration' placeholder='Enter duration in seconds (4, 25, 40, etc...)' /> 
 
    </div> 
 
    <div class='col-sm-4'> 
 
     <button class='btn' id='scrollTopButton'>Scroll to top</button> 
 
    </div> 
 
    </div> 
 
</div>

Zobacz CodePen Demo

Aktualizacja

można spróbować to jeśli po prostu chcesz, aby dostosować prędkość i zachować stałą przewijanie zachowanie:

function pageScroll(speed) { 
    window.scrollBy(0,1); 
    scrolldelay = setTimeout(pageScroll,speed); 
} 

a następnie wywołać funkcję z prędkością wybraną t j .:

pageScroll(1); 

wpadłem jej w Chrome, a nie opodatkować moje użycie procesora. Procesor robi więcej skoków, gdy jest uruchamiany w Firefoksie.

+0

Ten kod wydaje się być jaśniejszy w procesorze, szybkość zależy od wysokości strony, ponieważ ustawiono czas przewijania, a nie szybkość przewijania. Aha i przewijanie nie powinno się zatrzymywać, kiedy dojdzie do dna. – Forivin

+0

Możesz wybrać miejsce, w którym chcesz przewinąć do tej funkcji, ale myślę, że to nie jest to, czego szukasz. Jeśli w dolnej części strony nie zatrzymuje się przewijanie, w jaki sposób zatrzymano przewijanie? Czy użytkownik przestaje przewijać? Czy to jest limit czasu? –

+0

@Forivin Zaktualizowałem swoją odpowiedź za pomocą mniejszej funkcji, która nie zwiększa zużycia procesora w Chrome. Jednak użycie procesora wzrasta, gdy jest uruchamiane w przeglądarce Firefox. –