前陣子例用 queue 做了許多東西,慢慢的發現,原生的 stop()
並非我想像中的樣子。
- 使用任何的動態效果,或是
delay()
這樣的效果,stop()
能使之停止。 - 使用
queue()
,stop()
能使之停止。 stop()
可以傳入兩個布林值,一個是clearQueue
,另一個是JumpToEnd
。
然而,我卻發現事實上並不是這樣。
-
stop() 僅可停止單一動態動態效果,若連續使用並不會停止後續動作。
例如:$('div').animate( { 'left' : '500px' } ).delay(1000).animate( { 'left' : '0px' } );
使用stop()
僅會停止紅色的區域,綠色區域會繼續執行,很不幸的,他不會停止! -
clearQueue:true 會清除所有關於動態效果的執行動作。
例如:$('div').animate(
{ 'left' : '500px' } ).delay(1000).animate( { 'left' : '0px' } );
使用stop(true)
停止所有動作,且會停在執行中的結果。但是如果你再次呼叫時,他會從頭開始執行。
問題來了,如果我在 .animate(
{ 'left' : '500px' } ) 之後才按下stop(true)
,然後再次呼叫時,因為會從頭開始執行的關係,所以 .animate(
{ 'left' : '500px' } ) 會再執行一次,這是動態效果中不想見到的,因為看起來會像是沒有在動作一樣(因為已經做完了)。
另外,倘若我在
.animate(
{ 'left' : '0px' } ) 之後按下stop(true)
,然後再次呼叫時,因為從頭開始執行的關係,他會重複上一次的動作,這也是效果中不想見到的,因為應該是繼續最後一個步驟。 -
JumpToEnd:true 會直接結束該段動態效果,並繼續往下執行。
例如:$('div').animate(
{ 'left' : '500px' } ).delay(1000).animate(
{ 'left' : '0px' } );
使用stop(false,true)
直接顯示紅色區域的結果,然後綠色區域會繼續執行,很不幸的,他依舊不會停止! -
clearQueue:true, JumpToEnd:true 清除所有關於動態效果的執行動作,並結束該段動態效果。
例如:$('div').animate(
{ 'left' : '500px' } ).delay(1000).animate(
{ 'left' : '0px' } );
使用stop(false,true)
直接顯示紅色區域
的結果,綠色區域會停止執行。但是如果你再次呼叫時,
他會從頭開始執行。問題跟第 2 點一樣,若再次呼叫時,他會從頭開始執行。 -
jQuery 1.4 之後新增了
.clearQuere()
,雖然方便,但是跟stop()
的問題是一樣的。
接著,我來說一下我所預期的 stop() 是怎麼樣的一個情況:
-
stop() 應該停止整段動態效果,所以他應該是 clearQueue:true, JumpToEnd:true 的狀態,至於動態執行的階段問題,應該由動態撰寫者自行決定是否重設。
-
clearQueue:true 應該更謹慎使用!由於會重設整段動態效果,所以執行階段問題一樣是要由撰寫者自行決定是否該重新設定。
-
JumpToEnd:true 完全誤導使用者對於 stop() 的概念與本身詞意!也許這是很嚴重的指責,但是我不得不這麼說,當你的動作在被按下 stop() 之後,卻被使用者發現還會執行後續動作,這不是很詭譎嗎!
-
clearQueue:true,
JumpToEnd:true 應該是預設值,而 stop() 應該被修改甚至消滅! -
.clearQueue()
並沒有好到哪去。
所以,我們來看看 jQuery 關於 stop()
的核心做了甚麼事情:
stop: function( clearQueue, gotoEnd ) {
var timers = jQuery.timers;
/// 剛剛說的,clearQueue: true 時會將整個 queue 清空
if ( clearQueue ) {
this.queue([]);
}
this.each(function() {
// go in reverse order so anything added to the queue during the loop is ignored
for ( var i = timers.length - 1; i >= 0; i-- ) {
if ( timers[i].elem === this ) {
/// 當 JumpToEnd:true 時,會直接結束該段 animate 的 setTimeout
if (gotoEnd) {
// force the next step to be the last
timers[i](true);
}
timers.splice(i, 1);
}
}
});
// start the next in the queue if the last step wasn't forced
/// 誰能告訴我,為什麼 JumpToEnd:false (預設值) 的時候,要執行下一個 queue 內容?
/// 所以我才說,stop() 這個指令的預設值,完全違背了本身的概念與詞意!
if ( !gotoEnd ) {
this.dequeue();
}
return this;
}
現在知道問題點了嗎?這個 stop()
的預設值所表現的行為,應該叫做 stopAndPlay()
才對!