我最近问了一个关于同一个函数的问题,它解决了我的探针问题,并指导我进行了一个tutoraial,因为我正在使用while循环,这意味着我的函数没有动画,只是冻结然后调整大小。这种新的方式,使用setTimeout应该工作。唯一的问题是它只是抓住新的尺寸而不是动画。根据萤火虫没有错误。这是我目前管理动画的代码部分。
// Resize in timeframe
// Work out distance
var widthdiff = width - parseInt(element.style.width);
var heightdiff = height - parseInt(element.style.height);
// Work out how miliseconds per step (100 in total)
var steptime = timeframe / 100;
// Work out how many pixels it needs to move each step
var widthpps = widthdiff / 100; // ERROR?
var heightpps = heightdiff / 100;
// Set up original sizes
var origwidth = parseInt(element.style.width);
var origheight = parseInt(element.style.height);
// Loop through all 100 steps setting a time out resize each time
var timers = [];
for(var i = 0; i < 100; i++)
{
timers[i] = setTimeout(function() { // ERROR?
element.style.width = origwidth + (widthpps * i) + 'px';
element.style.height = origheight + (heightpps * i) + 'px';
}, i * steptime);
}
争论被传递得很好,我已经测试了所有这些,我曾经让它动画一次,只是错了。所以我的问题将接近名为ERROR的评论?我相信。谢谢你的帮助。
答案 0 :(得分:5)
问题是变量“i”将被所有超时函数共享。
您可以编写单独的函数来构建超时函数,或者可以将函数包装在内:
timers[i] = setTimeout((function(privateEye) {
return function() {
element.style.width = origwidth + (widthpps * privateEye) + 'px';
element.style.height = origheight + (heightpps * privateEye) + 'px';
})(i), i * steptime);
当我说“i”将被“共享”时,我的意思是你在循环中构建的每个函数都将正确引用该循环变量。但是那个变量发生了什么?它在循环的每次迭代中都在变化。重要的是要理解这些函数将引用真实“i”变量,而不是冻结副本。通过使用 second 函数,如上所述,您可以在循环中使用“i”的副本。
答案 1 :(得分:1)
我还没有完全审核过代码,但是有一个错误符合您的症状:
timers[i] = setTimeout(function() { // ERROR?
element.style.width = origwidth + (widthpps * i) + 'px'; // <== error
element.style.height = origheight + (heightpps * i) + 'px'; // <== error
}, i * steptime);
问题是这些函数会收到实时引用到i
,而不是它的循环迭代值的副本。所以他们都看到i
的最后一个值。
这很容易解决:
timers[i] = setTimeout(makeStepFunction(i), i * steptime);
// Anywhere in the surrounding function, not in the loop:
function makeStepFunction(step) {
return function() {
element.style.width = origwidth + (widthpps * step) + 'px';
element.style.height = origheight + (heightpps * step) + 'px';
};
}
现在setTimeout
将调用的函数正在使用传递给makeStepFunction
的参数,而不是i
。
你可以在没有命名函数的情况下执行此操作,但它会非常快速地混淆:
timers[i] = setTimeout((function(step) {
return function() {
element.style.width = origwidth + (widthpps * step) + 'px';
element.style.height = origheight + (heightpps * step) + 'px';
};
})(i), i * steptime);
这一切都与闭包(“关闭”数据的功能)如何在JavaScript中工作有关。它们真的很强大,但一旦你知道它们是如何工作的,它们并不复杂。 FWIW,我的博客文章 Closures are not complicated 可能会有所帮助。一旦你知道它们是如何工作的,它们就会失去神秘感(并且变得更加有用)。
答案 2 :(得分:1)
另一种解决方案是使用setInterval并使该方法使用在每次传递时更新的全局i以及取消setInterval的截止值。
var i = 0;
var interval = setInterval(
function() {
element.style.width = origwidth + (widthpps * i) + 'px';
element.style.height = origheight + (heightpps * i) + 'px';
i++;
if(i==100)
clearInterval(interval); //Stops executing
}, stepTime);
找到关于setTimeout和setInterval如何工作的一些解释,以查看哪个最适合您的目的。 http://ejohn.org/blog/how-javascript-timers-work/