setTimeout函数似乎总是给我带来麻烦。现在我有一个递归函数(通过setTimeout调用自身)并更改元素高度。
该函数发送两个参数:要更改的元素和元素的最大高度。该功能的目的是展开元素,或以恒定的速度“向下滑动”。我知道我可以用jQuery解决这个问题,但我正在尝试自己的功能。
function slide_down(element, max_height)
{
if(element.clientHeight < max_height)
{
var factor = 10;
var new_height = (element.clientHeight + factor >= max_height) ? max_height : (element.clientHeight + factor);
element.style.height = new_height + 'px';
var func_call = 'slide_down(' + element + ', ' + max_height + ');';
window.setTimeout(func_call, 10);
}
}
我在最初调用函数时测试了参数。 max_height设置为20,因为它是所需的高度元素(我从.scrollHeight获得此值)。
当函数完成后,我想让它自己调用,直到max_height是元素的高度。我用这个setTimeout调用来做到这一点:
var func_call = 'slide_down(' + element + ', ' + max_height + ');';
window.setTimeout(func_call, 10);
它不起作用。这确实有效:
var func_call = 'alert(1);';
window.setTimeout(func_call, 10);
我也尝试将函数调用直接放入setTimeout语句中,但仍无法正常工作。
请注意,元素的高度会改变第一次迭代,函数永远不会调用自身。所以元素变量设置正确,我使用alert()来显示max_height也是正确的。
alert(func_call);
提醒:
slide_down([object HTMLParagraphElement], 20);
答案 0 :(得分:19)
执行此操作时:
var func_call = 'slide_down(' + element + ', ' + max_height + ');';
你将元素转换为字符串,所以你的超时看起来像是
slide_down("[Object]", 100);
显然无效。
你应该做的是创建一个闭包 - 它有点复杂,但基本上你创建了一个函数,旧函数中的局部变量仍然在新函数中可用。
function slide_down(element, max_height)
{
if(element.clientHeight < max_height)
{
var factor = 10;
var new_height = (element.clientHeight + factor >= max_height) ? max_height : (element.clientHeight + factor);
element.style.height = new_height + 'px';
var func = function()
{
slide_down(element, max_height);
}
window.setTimeout(func, 10);
}
}
10还有一点暂停 - 我建议至少使用50。
答案 1 :(得分:3)
首先,这个“现在我有一个递归的函数(通过setTimeout调用自己)”“如果你没有改变周期,就会尖叫 setInterval 。” / p>
其次,这是因为元素引用在字符串concat中丢失,因为element.toString()将是“[object]”。尝试传入一个你可以重新找到的id,存储一个级别的引用,或者(我刚刚看到matt b指出)扩展的方法表单。
答案 2 :(得分:2)
编写方法的一种更微妙的方式(作为Gregs答案的扩展):
function slide_down(element, max_height)
{
if(element.clientHeight < max_height)
{ return; }
var factor = 10,
new_height = element.clientHeight + factor,
f = arguments.callee;
if( new_height > max_height )
{ new_height = max_height; }
element.style.height = new_height + 'px';
window.setTimeout(function() { f(element, max_height); }, 10);
}
此示例代码的真正优势是使用arguments.callee
。这样你就不会破坏你的功能,如果你决定重命名它。我还简化了new_height
值分配。旧代码中的问题是您执行了两次element.clientHeight + factor
,这有点无关紧要。并不是说在这种情况下它对你的表现有任何明显的影响。但是,避免一遍又一遍地计算相同的事情总是好的,但只是存储结果供以后使用。
答案 3 :(得分:1)
我有类似的经历。当你下次传递元素时,它会在函数调用中转换为字符串,所以当函数运行时,它会尝试找到一个名为[object] .string的元素,而不是你想要的东西。< / p>
尝试更改函数参数以获取元素的id,并在函数内部首先调用document.getElementById()。
答案 4 :(得分:1)
您的代码存在的问题是您无法传递元素参数。
而不是:
var func_call = 'slide_down(' + element + ', ' + max_height + ');'; window.setTimeout(func_call, 10);
尝试使用匿名函数:
window.setTimeout(function() { slide_down(element, max_height) }, 10);
@ matt.b:IE中不支持传入setTimeout调用的参数(你的方式)。
答案 5 :(得分:0)
两件事:
1。还有另一种方法可以调用setTimeout()
来传递函数和参数,而不是要执行的字符串。事实上,the Gecko DOM manual states表示不建议使用您的setTimeout()
版本。
而不是:
var func_call = 'slide_down(' + element + ', ' + max_height + ');';
window.setTimeout(func_call, 10);
请改为尝试:
window.setTimeout(slide_down, 10, element, max_height);
更新 :正如RoBorg所说,这在IE中可能不起作用,所以你不妨忽略它。
2。我有一种感觉,在setTimeout()
被自己调用的函数中调用setTimeout()
要么不允许,要么不能正常工作。我假设您正在链接这样的调用,因为您希望代码重复执行?如果是这样,那就是window.setInterval()
的用途。