<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);
};
在while外读下i,你会发现是6.你这个定时器相当于在外面获取i,建议题主了解下js作用域
setTimeout 是异步机制。
首先你对i的使用就是不对的,如一楼所说,你这样写的每一个 i 都会是等于6(你可以在tom()里输出 i 试试~)
相对正确的写法是
此外,你这么写 while 会循环 6 遍,而你的 HTML 中只有五个元素,在最后一遍循环中会获取不到元素,也会报错。
这个修改可以
while(i<5)
,也可以var i = 1;
,然后把i++;
放到 while 循环的最后面。[补充]while循环里延时不是直白的这么想就可以的,具体原因其他答案也写的很明白了,要实现效果的话,建议还是用立即调用函数表达式来搞比较方便。
楼上正解。
这是一个经典的坑。
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函数内部执行,也可以实现同样的效果
因为你这么写,
当然找不到啦
就是执行到i=5 的时候,马上加1 ,i就是6了,已经超出你的img访问了把
函数
tom
是函数t
里面的函数, 且用了t
里面的变量i
,tom
是一个闭包,tom
和t
的变量i
是一样的。setTimeout
是异步机制,当执行到setTimeout(tom,3000)
时并不是等待3秒后执行tom
函数,而是循环继续,等到3秒后调用
tom
,此时循环早已结束,i
的值为6,所以document.getElementById('x'+i)
是找不到的。异步和闭包在js中都是很重要的。
这样写就对了,另外 setTimeout 里面使可以直接写函数的,不一定非要写成字符串