Forum Moderators: open
and I want to try and recreate a stripped down version for a list of links.
Here's how I've structured my code. I'm guessing you can see what I'm trying to get at - can someone take a look at it and point me in the right direction? JFTR, it causes a "too much recursion" error at the moment,
##############################################################
JAVASCRIPT
<!--
//--------------------------------------------------------------
//FUNCTION animateLink
//--------------------------------------------------------------
function animateLink(element,value)
{//clear out any backlog of commands on mouse events
if(element.movement)
{
clearTimeout(element.movement);
}
//acquire xpos from offsetLeft (style.left returns nothing?)
xpos = element.offsetLeft;
//define upper limit of xpos
final_x = value;
//define exit condition
if (xpos == final_x)
{
return true;
}
//increment xpos values until they reach the desired point
if (xpos < final_x)
{
xpos++;
}
if (xpos > final_x)
{
xpos--;
}
//assign incremented value to element's style
element.style.left = xpos + "px";
//use setTimeout to iterate the function until it reaches it's desired state
element.movement = setTimeout(animateLink(element), 40)
}
//--------------------------------------------------------------
//FUNCTION prepareMenu
//--------------------------------------------------------------
function prepareMenu()
{
//acquire document objects
var menu = document.getElementById("menu");
var links = menu.getElementsByTagName("li");
//define events and call respective functions
for(var i = 0; i<links.length; i++)
{
links[i].onmouseover = function()
{
var value = 100;
animateLink(this,value);
}
links[i].onmouseout = function()
{
var value = 0;
animateLink(this,value);
}
}
}
//LOAD SCRIPTS
//-------------------------------------------------------------
window.onload = (prepareMenu);
//-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" media="screen" type="text/css" href="css/screenMenu.css" />
<script type="text/javascript" src="./javascript/animMenu.js"></script>
</head>
<body>
<div id="wrapper">
<!--.........................HEADER......................-->
<div id = "masthead">
<h1>Masthead</h1>
</div>
<!--.........................CONTENT......................-->
<div id= "content">
<ul id = "menu">
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
<li>Item Four</li>
<li>Item Five</li>
<li>Item Six</li>
</ul>
</div>
</div>
<!--.........................FOOTER......................-->
<div class="push">
</div>
</div>
<div id="footer">
<div class="sub-footer">
<p>footer content</p>
</div>
</div>
</body>
</html>
#menu
{
width: 200px;
float: left;
clear: left;
}#menu li
{
position: relative;
clear: left;
}
#footer
{
clear: left;
}
I experimented with alerts in the animateLink function to reveal what's happening. It's definitely receiving an event from an LI object (although I've struggled to obtain any other values from that object node). I've tried passing the i value from prepareMenu to this function and alerting it to see if it's picking it up, but it's always a 6, which is a bit wierd. Also, I can't seem to acquire a 'style.left' value in the animateLink function.
Can anyone take a look and explain what's wrong here?
[edited by: coopster at 4:03 pm (utc) on Jan. 30, 2009]
[edit reason] no urls please TOS [webmasterworld.com] [/edit]
function animateLink(element,value) {
if (element.movement) {
window.clearInterval(element.movement);
}
xpos = element.offsetLeft;
element.movement = window.setInterval(function () {
if (xpos == value) {
window.clearInterval(element.movement); element.movement=false;
} else if (xpos < value) {
xpos++;
} else if (xpos > value) {
xpos--;
}
element.style.left = xpos + "px";
}, 40);
}function prepareMenu() {
//acquire document objects
var menu = document.getElementById("menu");
var links = menu.getElementsByTagName("li");
//define events and call respective functions
for (var i = 0; i < links.length; i++) {
links[i].onmouseover = function () {
animateLink(this,100);
};
links[i].onmouseout = function () {
animateLink(this,0);
};
}
}window.onload = prepareMenu;
I've tried passing the i value from prepareMenu to this function and alerting it to see if it's picking it up, but it's always a 6, which is a bit wierd.
The reason for that is that i is being evaluated from the li element. At the time that i is evaluated from the li element (who's mouseover or mouseout function does retain a pointer back to i within the prepareMenu function the way you would have been trying to assign i to an alert within the li's mouseover/mouseout, that is actually a 'bad' sort of closure which can cause memory leaks) the for loop has finished running and i's value will be read the same from all li elements. The solution to that is to make 'good' use of a closure which returns the value of i and stores it in the returned mouseover function, thereby the mouseover function does not need to retain it's pointer back to the prepareMenu function. Here is an example:
<html>
<head>
<title></title>
<script type="text/javascript">window.onload = function () {
var lis = document.getElementsByTagName('li');
for (var i = 0; i < lis.length; i++) {
//using a closure, the value of i is captured and evaluated,
//each time through the loop the outer mouseover function evaluates
//and stores the value of i in the inner function and returns the
//inner function as the value of the lis[i] mouseover
//think of the outer function wrapped in parens as an egg shell which
//gets cracked every time through the loop and spills egg into the inner function
lis[i].onmouseover = (function (egg) {
return function () {
alert(egg);
};
})(i); //i gets passed in to the arg parameter and the anonymous function (with arg parameter) is invoked//the mousout alert will always alert 3, i's final value at end of loop
lis[i].onmouseout = function () {
alert(i); //retains a pointer back to i in the prepareMenu function
};
}
};</script>
</head>
<body>
<ul style="width:50px;">
<li>li one</li>
<li>li two</li>
<li>li three</li>
</ul>
</body>
</html>