在網上瞄到篇文章關於 jQuery 中的事件延時執行 ,作者講的這個菜單問題,之前寫一個菜單控件時處理過,有印象。這不是要說的重點,重點是,在jquery代碼中,要實現延時執行一段代碼,可以有更“jquery style”的寫法,比直接用window.setTimeout/window.setInterval這種“江南style”要優雅一點點,即可利用jquery的功能避免延時后執行環境變化帶來的問題(需做閉包處理),又可保持jquery鏈。這種方法就是使用animate()函數及它支持的callback功能。
動畫有兩個元素,1是要變化的效果,2是變化的時間跨度,如果變化效果取空,那animate就變成一個能延時執行callback的定時器了:
$div.animcate({'top':'+=0'},1000,'linear',
function(){
$( this).text('It is time to change!'); // this指針仍是jquery對象所指
});
$( this).text('It is time to change!'); // this指針仍是jquery對象所指
});
//試過效果參數用空{}不行,用{'':''}在ie7、8下不行
此外,jquery有一個.delay( duration [, queueName] ) 函數可直接用於動畫過程中的延時環節,不過它沒有callback參數,不能直接用來做定時器。但是進一步玩味一下,發現可以和queue()/dequeue()聯合起來實現更優雅的寫法:
$div.delay(1000).queue(
function(){
$( this).text('It is time to change!');
});
$( this).text('It is time to change!');
});
以下是我把剛好在做的一段代碼重構了的例子(實現的是一個動畫刷新一串數字的效果):
View Code
//
原來的代碼,使用raw api -- window.setInterval
$( ' div.numbers ').each(function (index, div) {
var $div = $(div);
var val = parseInt($div.data( ' value '));
if (!val)
return;
var steps = getSteps(val);
$div.text(steps[ 0]);
if (steps.length > 1) {
var interval = 20,
stepIndex = 1;
var intervalHandler = window.setInterval(function () {
$div.text(steps[stepIndex]);
if (stepIndex++ == steps.length) {
window.clearInterval(intervalHandler);
delete intervalHandler;
}
else {
$div.animate({ ' fontSize ': ' 72px ', ' top ': ' 6px ' }, 30)
.animate({ ' fontSize ': ' 64px ', ' top ': ' 10px '}, 20);
}
}, interval);
}
})
//
$( ' div.numbers ').each(function (index, div) {
var $div = $(div);
var val = parseInt($div.data( ' value '));
if (!val)
return;
var steps = getSteps(val);
$div.text(steps[ 0]);
if (steps.length > 1) {
var interval = 20,
stepIndex = 1;
var intervalHandler = window.setInterval(function () {
$div.text(steps[stepIndex]);
if (stepIndex++ == steps.length) {
window.clearInterval(intervalHandler);
delete intervalHandler;
}
else {
$div.animate({ ' fontSize ': ' 72px ', ' top ': ' 6px ' }, 30)
.animate({ ' fontSize ': ' 64px ', ' top ': ' 10px '}, 20);
}
}, interval);
}
})
//
View Code
//
重構后的代碼
var animateStep = function ($div) {
var steps = $div.data('steps'),
stepIndex = $div.data('stepIndex');
$div.text(steps[stepIndex]);
if (++stepIndex < steps.length) {
$div.data('stepIndex', stepIndex)
.delay(20)
.animate({ 'fontSize': '72px', 'top': '-=4px', 'left': '-=4px' }, 20)
.animate({ 'fontSize': '64px', 'top': '+=4px', 'left': '+=4px' }, 10)
.queue( function () { $div.dequeue();animateStep($div); });
}
}
$('div.numbers').each( function (index, div) {
var $div = $(div);
var val = parseInt($div.data('value'));
if (!val)
return;
$div.data('steps', getSteps(val))
.data('stepIndex', 0);
animateStep($div);
})
//
var animateStep = function ($div) {
var steps = $div.data('steps'),
stepIndex = $div.data('stepIndex');
$div.text(steps[stepIndex]);
if (++stepIndex < steps.length) {
$div.data('stepIndex', stepIndex)
.delay(20)
.animate({ 'fontSize': '72px', 'top': '-=4px', 'left': '-=4px' }, 20)
.animate({ 'fontSize': '64px', 'top': '+=4px', 'left': '+=4px' }, 10)
.queue( function () { $div.dequeue();animateStep($div); });
}
}
$('div.numbers').each( function (index, div) {
var $div = $(div);
var val = parseInt($div.data('value'));
if (!val)
return;
$div.data('steps', getSteps(val))
.data('stepIndex', 0);
animateStep($div);
})
//
