简体   繁体   中英

Scrolling with an easing function

I have written a function that when invoked, will scroll the page downwards in a smooth fashion.

The problem is that the amount scrolled is not precise. It can be off by one pixel or so depending on the distance scrolled and the duration of the scroll.

Is there a better way to do this such that the scroll can move the exact number of desired pixels?

 const EASING = BezierEasing(0, .1, .1, 1); // Example values. const DURATION = 1000; // ms. document.addEventListener('DOMContentLoaded', () => { document.querySelector('#foo') .addEventListener('click', onClick, false); }); function onClick(e) { scroll(400); // px. e.preventDefault(); return false; } function scroll(distance) { var start, travelled, html; start = performance.now(); travelled = 0; html = document.querySelector('html'); (function move(now) { var fractionDone, dy, toMove; fractionDone = (now-start) / DURATION; if((1 - fractionDone) <= 0) { return; // Done! } if(window.scrollY + window.innerHeight === html.offsetHeight) { return; // At bottom of page. } dy = ((EASING.get(fractionDone)) * distance); toMove = Math.floor((dy - travelled)); // `scrollBy` only accepts integers. if(toMove > 0) { window.scrollBy(0, toMove); travelled += toMove; } requestAnimationFrame(move); }(start)); } 
 <!DOCTYPE html> <html> <head> <script src="https://rawgit.com/gre/bezier-easing/master/build.js"></script> </head> <body> <a href id="foo">Click Me!</a> <script> /* print some numbers to the DOM to help visualize the scrolling */ var body = document.querySelector('body'); for(var x = 0; x < 50; x++) { var div = document.createElement("div"); var text = document.createTextNode(x); div.appendChild(text); body.appendChild(div); } </script> </body> </html> 

could you do something like this to account for the last iteration?

basically if toMove gets rounded down to 0, but distance hasnt been travelled yet, force it to do scroll one more?

if(toMove > 0 || (toMove == 0 && travelled != distance) {
  window.scrollBy(0, (toMove ? toMove : 1));
  travelled += toMove;
}

I decided to modify the done logic to move any remaining distance:

// ...
if((1 - fractionDone) <= 0) {
  window.scrollBy(0, (distance - travelled)); // Scroll any remaining distance.
  return; // Done!
}
// ...

Which, I think, solves the issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM