Jquery 动画问题与潜在的变量范围问题?
我已经写了一个我的问题的例子,由于某种原因(我猜我似乎没有完全理解),我的变量正在失去范围。我正在尝试为屏幕上的几件事设置动画,一旦它们到达目的地,animate() 中的“完整”函数就会启动,这意味着基本上删除 dom 元素以及其他几个意味着的函数被延迟在其中。一个好方法是把它想象成枪射击,在子弹击中时而不是击中之前造成伤害,并且子弹造成的伤害与动画本身相关。
正如我在第一句话中提到的,我写了一个例子来准确地演示我的意思。我还将粘贴它附带的 console.log 输出,并给出其显示内容的摘要。
我已将示例放在 jsbin 中,因为你们应该更容易看到(我希望 - 我以前从未使用过这些东西)。对于我的示例,我只是制作了一个方块填充的动画,以及一些方块在其附近飞行。当这些方块到达目的地时,它会从“罐子”中清空一些并重置其动画,然后将自己从 dom 中移除。
这是来自 chrome 的 console.log 文本:
Set Height to: 30px
Testing.Start( [Object] )
Setup #I63326848.animate()
Setup #I22596539.animate()
Setup #I14561405.animate()
Setup #I57372916.animate()
Setup #I31994195.animate()
OnComplete for :I63326848
Set Height to: 30.6px
OnComplete for :I14561405
Set Height to: 33px
OnComplete for :I57372916
Set Height to: 34.2px
OnComplete for :I31994195
Set Height to: 36px
OnComplete for :I63326848
Set Height to: 36.6px
Finished filling
正如你所见从上面的日志中看到,#I22596539(第二个)已设置,但是当涉及到 OnComplete 方法时,它没有触发,所有其他方法都触发了,#I63326848 触发了两次(第一种方法设置)。我还注意到,当我删除方框(#Jar)上链的 .stop() 部分时,这些问题不会发生。然而这是必要的,所以我不会最终看到几个动画试图同时填充罐子。我还注意到,它总是要设置的第二个动画来执行此操作。
所以我不完全确定它是否是变量失去了范围,否则这肯定会发生在其他人身上,我在过去的几天里试图解决这个问题,但我遇到了障碍。我已经没有办法尝试修复它了。你们是我最后的希望!
function Jar() {
this._iAmount = 50;
this._iMaxAmount = 100;
this._iRefillRate = 5;
return this;
}
Jar.prototype = {
ReduceAmount: function( m_iAmount ) {
this._iAmount -= m_iAmount;
if( this._iAmount < 0 ) {
this._iAmount = 0;
}
return;
},
StartFill: function() {
var iHeight = ( 60 - ( 60 * this._iAmount / this._iMaxAmount ) );
console.log( "Set Height to: "+iHeight+"px" );
jQuery( '#Jar' ).css( 'height', iHeight+'px' );
if( iHeight < 60 ) {
var iMillisecondsTilMax = ( ( this._iMaxAmount - this._iAmount ) / this._iRefillRate ) * 1000;
jQuery('#Jar').stop().animate({height: '0px'}, iMillisecondsTilMax, function() { console.log( "Finished filling" ); } );
}
return;
}
};
var Testing = {
Start: function( m_oJar ) {
console.log( "Testing.Start( [Object] )" );
for( var iLoop = 0; iLoop < 5; iLoop++ ) {
var elNewDiv = document.createElement('div');
var iRandomValue = Math.round( 1 + ( Math.random() * ( 99999999 - 1 ) ) );
var iAmount = Math.round( 1 + ( Math.random() * ( 5 - 1 ) ) );
var strID = "I"+iRandomValue;
elNewDiv.setAttribute( 'id', strID );
elNewDiv.style.border = 'solid 1px red';
elNewDiv.style.position = "absolute";
elNewDiv.style.height = '200px';
elNewDiv.style.width = '200px';
elNewDiv.style.left = '0px';
elNewDiv.style.top = '0px';
document.body.appendChild( elNewDiv );
this.Animate( m_oJar, strID, iAmount );
}
return;
},
Animate: function( m_oJar, m_strID, m_iAmount ) {
console.log( "Setup #"+m_strID+".animate()" );
jQuery( '#'+m_strID ).animate({ width: '30px', height: '30px', top: '100px', left: '200px' }, {
duration: 1000,
queue: false,
easing: 'linear',
complete: function() {
console.log( "OnComplete for :"+m_strID );
m_oJar.ReduceAmount( m_iAmount );
m_oJar.StartFill();
jQuery( '#'+m_strID ).remove();
}
});
}
};
jQuery(document).ready( function() {
var oJar = new Jar();
oJar.StartFill();
Testing.Start( oJar );
});
I've written an example of my problem, for some reason (which I don't seem to fully understand I guess), my variables are losing scope. I'm trying to animate several things on the screen, once they've reached their destination the 'complete' function within animate() kicks in, this is meant to basically delete the dom element as well as a couple other functions that are meant to be delayed within it. A good way to think of it is a gun firing, do the damage when the bullet hits and not before, and the damage the bullet does is tied into the animation itself.
As I mentioned in my first sentence, I've written an example to demonstrate exactly what I mean. I'll also paste in the console.log output that came with it and give a summary of what it shows.
I've placed the example in jsbin, as it should be easier for you guys to see (I hope -- I've never used that stuff before). For my example I just did an animation of a square block filling, and some squares flying near it. When those squares reach its destination, it empties some out of the 'Jar' and resets its animation, then it removes itself from the dom.
Here's the console.log text from chrome:
Set Height to: 30px
Testing.Start( [Object] )
Setup #I63326848.animate()
Setup #I22596539.animate()
Setup #I14561405.animate()
Setup #I57372916.animate()
Setup #I31994195.animate()
OnComplete for :I63326848
Set Height to: 30.6px
OnComplete for :I14561405
Set Height to: 33px
OnComplete for :I57372916
Set Height to: 34.2px
OnComplete for :I31994195
Set Height to: 36px
OnComplete for :I63326848
Set Height to: 36.6px
Finished filling
As you can see from the log above, #I22596539 (2nd one) was set up, however when it came to the OnComplete methods, it did not fire, all the others did and #I63326848 fired twice (1st method setup). I've also noticed that when I remove the .stop() part of the chain on the squared box (#Jar), that these problems do not happen. However that is needed so I don't end up with several animations trying to fill the jar at the same time. I've also noticed that it's ALWAYS the second animation to be set up that does this.
So I'm not entirely sure if it's variables losing scope, else surely this would happen to the others, I've sent the last couple of days trying to suss this one out and I've hit my road block. I've ran out of things to try to fix it. You guys are my last hope!
function Jar() {
this._iAmount = 50;
this._iMaxAmount = 100;
this._iRefillRate = 5;
return this;
}
Jar.prototype = {
ReduceAmount: function( m_iAmount ) {
this._iAmount -= m_iAmount;
if( this._iAmount < 0 ) {
this._iAmount = 0;
}
return;
},
StartFill: function() {
var iHeight = ( 60 - ( 60 * this._iAmount / this._iMaxAmount ) );
console.log( "Set Height to: "+iHeight+"px" );
jQuery( '#Jar' ).css( 'height', iHeight+'px' );
if( iHeight < 60 ) {
var iMillisecondsTilMax = ( ( this._iMaxAmount - this._iAmount ) / this._iRefillRate ) * 1000;
jQuery('#Jar').stop().animate({height: '0px'}, iMillisecondsTilMax, function() { console.log( "Finished filling" ); } );
}
return;
}
};
var Testing = {
Start: function( m_oJar ) {
console.log( "Testing.Start( [Object] )" );
for( var iLoop = 0; iLoop < 5; iLoop++ ) {
var elNewDiv = document.createElement('div');
var iRandomValue = Math.round( 1 + ( Math.random() * ( 99999999 - 1 ) ) );
var iAmount = Math.round( 1 + ( Math.random() * ( 5 - 1 ) ) );
var strID = "I"+iRandomValue;
elNewDiv.setAttribute( 'id', strID );
elNewDiv.style.border = 'solid 1px red';
elNewDiv.style.position = "absolute";
elNewDiv.style.height = '200px';
elNewDiv.style.width = '200px';
elNewDiv.style.left = '0px';
elNewDiv.style.top = '0px';
document.body.appendChild( elNewDiv );
this.Animate( m_oJar, strID, iAmount );
}
return;
},
Animate: function( m_oJar, m_strID, m_iAmount ) {
console.log( "Setup #"+m_strID+".animate()" );
jQuery( '#'+m_strID ).animate({ width: '30px', height: '30px', top: '100px', left: '200px' }, {
duration: 1000,
queue: false,
easing: 'linear',
complete: function() {
console.log( "OnComplete for :"+m_strID );
m_oJar.ReduceAmount( m_iAmount );
m_oJar.StartFill();
jQuery( '#'+m_strID ).remove();
}
});
}
};
jQuery(document).ready( function() {
var oJar = new Jar();
oJar.StartFill();
Testing.Start( oJar );
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我没有一个很好的答案,但我认为这可能是一个 jQuery 错误。我已经能够通过修改 StartFill 方法来解决这个问题,或者只是不在 read() 函数中第一次调用它。当我使用调试器时,我也看到它消失了,调试器倾向于某种计时问题......可能在 jQuery 中,可能在浏览器中。除了 Chrome 之外,我还没有在其他任何设备上测试过这一点,所以很难确定。但是我不认为您提供的代码中的逻辑有任何问题。
I don't have a great answer, but I think this might be a jQuery bug. I have been able to work around the issue by modifying the StartFill method, or just not calling it the first time in the ready() function. I've also seen it go away when I use the debugger which leans towards some sort of timing issue...possibly in jQuery, possibly in the browser. I've not tested this on anything other than Chrome so it's hard to be sure. However I don't think there is anything wrong with the logic in your code provided.