I wrote a script to scroll pages when menu buttons are clicked, similar effect like: http://css-tricks.com/examples/SmoothPageScroll
var m1 = document.getElementById('m1'),
m2 = document.getElementById('m2'),
m3 = document.getElementById('m3'),
m4 = document.getElementById('m4'),
m5 = document.getElementById('m5'),
m2PositionY = document.getElementById('id2').offsetTop,
m3PositionY = document.getElementById('id3').offsetTop,
doneValue = true,
windowPageYOffset = 0;
function Scroll(ScrollValue1) {
windowPageYOffset = window.pageYOffset;
if(windowPageYOffset == ScrollValue1) {
doneValue = true;
}
// scroll up
else if(windowPageYOffset >= ScrollValue1) {
window.scrollBy(0, -(1 + ((windowPageYOffset - ScrollValue1) / 10)));
}
// scroll down
else {
window.scrollBy(0, 1 + ((ScrollValue1 - windowPageYOffset) / 10));
}
if(windowPageYOffset != ScrollValue1) {
var setTimeoutScrollValue1 = setTimeout('Scroll(' + ScrollValue1 + ')', 20);
}
}
function doneOrNot(doneOrNotValue1) {
if(doneValue && doneOrNotValue1 != windowPageYOffset) {
Scroll(doneOrNotValue1);
doneValue = false;
}
}
m1.onclick = function () {
doneOrNot(0); // no need for a id since top is allways 0
}
m2.onclick = function () {
doneOrNot(m2PositionY);
}
m3.onclick = function () {
doneOrNot(m3PositionY);
}
I am using a "true or false variable" (doneValue
) to determine if previous Scroll
is finished before next can start. I wonder if there is any better method to do this in JavaScript?
Please give other feedback if you have any :)
1 Answer 1
There are a few things you can do differently
- Animations are most often accomplished by getting the difference between start and end values, and animating a factor from zero to 1. Multiply that with the difference, and you get an offset.
- Instead of relying on an interval (which may be slow, since JS is single-threaded), most animation libraries compare the start time to the current time, to see how far along the animation should be.
- Instead of waiting for the animation to stop and a boolean to flip, you can clear the animation's timer, and forcibly stop the animation, before starting a new one. That way the user's clicks aren't ignored, but override previous clicks instead.
Here's an alternative implementation using that approach and other good stuff:
var smoothScrollTo = (function () {
var timer, start, factor;
return function (target, duration) {
var offset = window.pageYOffset,
delta = target - window.pageYOffset; // Y-offset difference
duration = duration || 1000; // default 1 sec animation
start = Date.now(); // get start time
factor = 0;
if( timer ) {
clearInterval(timer); // stop any running animation
}
function step() {
var y;
factor = (Date.now() - start) / duration; // get interpolation factor
if( factor >= 1 ) {
clearInterval(timer); // stop animation
factor = 1; // clip to max 1.0
}
y = factor * delta + offset;
window.scrollBy(0, y - window.pageYOffset);
}
timer = setInterval(step, 10);
return timer; // return the interval timer, so you can clear it elsewhere
};
}());
Another advantage of always animating a factor between zero and 1 is that you can run it through other expressions, and (for instance) animated the scroll with a sine wave.
-
\$\begingroup\$ I refactored out the general animation logic from the specific act of scrolling and added support for easing functions. \$\endgroup\$Bill Barry– Bill Barry2012年06月27日 14:47:12 +00:00Commented Jun 27, 2012 at 14:47
-
\$\begingroup\$ And added back in the canceling animation functionality: jsfiddle.net/DruwJ/3 \$\endgroup\$Bill Barry– Bill Barry2012年06月27日 14:56:39 +00:00Commented Jun 27, 2012 at 14:56
-
\$\begingroup\$ Very nice, but it seems you're assigning
change = to - from
before you've checked thefrom
andto
arguments. I think you're going to get some NaN-nonsense there if you omit thefrom
andto
args but include an easing function. \$\endgroup\$Flambino– Flambino2012年06月27日 15:19:55 +00:00Commented Jun 27, 2012 at 15:19 -
\$\begingroup\$ Good catch \$\endgroup\$Bill Barry– Bill Barry2012年06月27日 16:52:42 +00:00Commented Jun 27, 2012 at 16:52
-
\$\begingroup\$ Thank you both so much! It looks really good! I have much to learn... Some questions: What does this "window.smoothScrollTo = function (...) {}" differ from "function smoothScrollTo(target, duration)"? Bill, can you show me a working example with easing out function? \$\endgroup\$user1087110– user10871102012年06月28日 07:49:04 +00:00Commented Jun 28, 2012 at 7:49