<html>
<style>
/* reset */
*{margin:0;padding:0;border:0;}
img{display:block;}
/* 布局 */
.container{width:400px;height:300px;position:relative;}
img{width:100%;position:absolute;top:0;}
/* 图像透明度&zindex */
img:nth-child(n){filter:alpha(opacity=1);opacity: 1;z-index:999;}
</style>
<script>
var t = function(){
var i = 0;
while(i<6){
i++;
var tom = function (){document.getElementById('x'+i).style.zIndex=9999;
setTimeout(tom,3000);
};
};
t();
</script>
<p class='container' id='id_container'>
<img id='x1' src='image/1.png'>
<img id='x2' src='image/2.png'>
<img id='x3' src='image/3.png'>
<img id='x4' src='image/4.png'>
<img id='x5' src='image/5.png'>
</p>
</html>
为什么一加上while循环,getElementById就找不到id了?
而且,我把定时器放在while里面,不是应该执行完setTimeout(tom,3000);才进入下一轮循环吗?
while(i<6){
i++;
var tom = function (){document.getElementById('x'+i).style.zIndex=9999;
setTimeout(tom,3000);
};
高洛峰2017-04-11 11:06:30
首先你对i的使用就是不对的,如一楼所说,你这样写的每一个 i 都会是等于6(你可以在tom()里输出 i 试试~)
相对正确的写法是
var i = 0;
while(i<6){
i++;
var tom = function (k){
document.getElementById('x'+k).style.zIndex=9999;
//console.log(k);
};
/*var ct = document.getElementById('id_container').style.z-index=50;
clearTimeout();
*/
//setTimeout(tom(i),3000); //误,`setTimeout`内不能加函数执行语句,应该为函数名`tom`,或者如下用引号包含起来的函数执行语句
setTimeout("tom("+ i + ")",3000);
};
此外,你这么写 while 会循环 6 遍,而你的 HTML 中只有五个元素,在最后一遍循环中会获取不到元素,也会报错。
这个修改可以 while(i<5)
,也可以 var i = 1;
,然后把 i++;
放到 while 循环的最后面。
[补充]while循环里延时不是直白的这么想就可以的,具体原因其他答案也写的很明白了,要实现效果的话,建议还是用立即调用函数表达式来搞比较方便。
var tom = function (nb){
//document.getElementById('x'+nb).style.zIndex=9999;
console.log(nb);
};
function test(){
var i =0;
(function(){
if(i>=5){
return;
}
//console.warn(i + "test");
i++;
tom(i);
window.setTimeout(arguments.callee,3000);
})();
}
test();
ringa_lee2017-04-11 11:06:30
楼上正解。
这是一个经典的坑。
1、要理解js是没有块级作用域的,只要函数作用域,由于你的tom()函数是在定时器里触发执行的,等它执行时whlie循环实际上已经执行完毕(while此时在全局作用域中,是在程序加载阶段就解释执行完的),此时i的值已经==6(当运行到i=5时,由于其小于6,所以执行了i++,i的值变成了6),而你的html代码中并没有id=x6的节点,所以你读取不到。解决办法:闭包——将tom函数放置在一个立即执行函数中:tom = (function(i){...})(i);
2、setTimeout函数在这里的用法就是错误的。我看到你的代码意图实际上是要实现类似于轮播图的效果,即每隔三秒用后面一张图片覆盖前面的图片,这里应该用setInterval,并且放在while循环外面。因为setTimeout并不会随着while循环一起执行。
===============================================
补充:或者,你可以将setTimeout放入tom函数内部执行,也可以实现同样的效果
PHP中文网2017-04-11 11:06:30
函数 tom
是函数 t
里面的函数, 且用了t
里面的变量 i
, tom
是一个闭包,tom
和t
的变量i
是一样的。
setTimeout
是异步机制,当执行到 setTimeout(tom,3000)
时并不是等待3秒后执行 tom
函数,而是循环继续,
等到3秒后调用 tom
,此时循环早已结束, i
的值为6,所以 document.getElementById('x'+i)
是找不到的。
异步和闭包在js中都是很重要的。
大家讲道理2017-04-11 11:06:30
while(i<6){
i++;
var tom = function (i){
return function(){
document.getElementById('x'+i).style.zIndex=9999;
}
}
setTimeout(tom(i),3000);
};
这样写就对了,另外 setTimeout 里面使可以直接写函数的,不一定非要写成字符串