I’m trying to write some JS replicating jQuery’s fadeIn and fadeOut functions. Here’s the code I have so far:
function fadeIn(elem, d, callback)
{
var duration = d || 1000;
var steps = Math.floor(duration / 50);
setOpacity(elem,0);
elem.style.display = '';
for (var i = 1; i <= steps; i++)
{
console.log(i/steps + ', ' + (i/steps) * duration);
setTimeout('setOpacity("elem", '+(i / steps)+' )', (i/steps) * duration);
}
if (callback)
setTimeout(callback,d);
}
function setOpacity(elem, level)
{
console.log(elem);
return;
elem.style.opacity = level;
elem.style.MozOpacity = level;
elem.style.KhtmlOpacity = level;
elem.style.filter = "alpha(opacity=" + (level * 100) + ");";
}
I’m having troubles with the first setTimeout call – I need to pass the object ‘elem’ (which is a DOM element) to the function setOpacity. Passing the ‘level’ variable works just fine… however, I’m getting “elem is not defined” errors. I think that’s because by the time any of the setOpacity calls actually run, the initial fadeIn function has finished and so the variable elem no longer exists.
To mitigate this, I tried another approach:
setTimeout(function() { setOpacity(elem, (i / steps));}, (i/steps) * duration);
The trouble now is that when the function is called, (i/steps) is now always 1.05 instead of incrementing from 0 to 1.
How can I pass the object in question to setOpacity while properly stepping up the opacity level?
Your first approach is evaluating code at runtime. You are most likely right about why it’s failing (
elemis not in the scope in which the code is eval’d). Using any form ofeval()(andsetTimeout(string, ...)is a form ofeval()) is a general bad idea in Javascript, it’s much better to create a function as in your second approach.To understand why your second approach is failing you need to understand scopes and specifically closures. When you create that function, it grabs a reference to the
ivariable from thefadeInfunction’s scope.When you later run the function, it uses that reference to refer back to the
ifromfadeIn‘s scope. By the time this happens however, the loop is over so you’ll forever just getibeing whatever it was when that loop ended.What you should do is re-engineer it so that instead of creating many setTimeouts at once (which is inefficient) you instead tell your setTimeout callback function to set the next Timeout (or you could use setInterval) and do the incrementing if your values inside that callback function.