實例講解Javascript緩動效果
我們這里將討論的是Javascript緩動效果的實現,這個看似沒有實際作用的功能,其實實現更多花樣繁多Javascript緩動效果的基石。
緩動,學名為Tween,緩沖移動的簡稱。要想頁面內容切換起來舒服,就使用淡入淡出特效,要想讓頁面元素動起來自然,就要使用Javascript緩動效果。這兩個混合起來,可以衍生多種特效的。感謝Flash開發人員為我們做了那么多先行研究,我們直接把它們拆出來裝在各種菜單與相冊中。我們先從最簡單的東西做起,加速與減速。
既然是緩動,它就一定涉及以下概念:距離,時間與速度。我們可以想象存在一條直線L,點A與點B就是L的起點與終點,有一個點C在直線L上移動,從點A到點B。所需的時間通常都是未知,但速度我們一定要制定。看下面的圖,我們想讓綠色的方塊在淡緊色的滑動帶上移動。滑動帶左上角就相當于點A,右上角就相當于B點,方塊的左上角就相當于點C,移動距離為兩者的寬度之差。由于我們移動的物體是存在寬度,也就是說點C永遠不可能與點B重合。但一個準確的目的地(為了方便,我們把它稱之為點D)是必須的,我們一定要計算它出來。因為在加速運動中,點C隨時可能超過點D,當點超過它時,我們就要終止此移動,并把點C拉回到點D上。
點擊可移動綠色方塊
為了獲取它們在頁面上的坐標與尺寸,getCoords()與getStyle()又到出場時間了。對不起,我實在沒有意思來炫耀我的函數。更何況getStyle()被砍去了不少東西,威力沒有以前那么強大。
01.
//輔助函數1
02.
var
getCoords =
function
(el){
03.
var
box = el.getBoundingClientRect(),
04.
doc = el.ownerDocument,
05.
body = doc.body,
06.
html = doc.documentElement,
07.
clientTop = html.clientTop || body.clientTop || 0,
08.
clientLeft = html.clientLeft || body.clientLeft || 0,
09.
top = box.top + (self.pageYOffset || html.scrollTop || body.scrollTop ) - clientTop,
10.
left = box.left + (self.pageXOffset || html.scrollLeft || body.scrollLeft) - clientLeft
11.
return
{
'top'
: top,
'left'
: left };
12.
};
13.
//輔助函數2
14.
var
getStyle =
function
(el, style){
15.
if
(!+
"\v1"
){
16.
style = style.replace(/\-(\w)/g,
function
(all, letter){
17.
return
letter.toUpperCase();
18.
});
19.
var
value = el.currentStyle[style];
20.
(value ==
"auto"
)&&(value =
"0px"
);
21.
return
value;
22.
}
else
{
23.
return
document.defaultView.getComputedStyle(el,
null
).getPropertyValue(style)
24.
}
25.
}
那么我們怎么移動呢?在Javascript只有讓它變為絕對定位對象,給它的top與left賦值。它就會立即移動到相應的坐標上。由于Javascript處理位置變化太有效率,根本不可能讓你有“移動”的感覺,感覺是直接從點C直接跳到點D。我們必須讓物體每移動一點點,就停一下,讓眼睛有個殘影。根據人眼睛的視覺停留效應,若前一幅畫像留在大腦中的印象還沒消失,后一幅畫像就接踵而至,而且兩副畫面間的差別很小,就會有“動”的感覺。那么停留多么毫秒最合適呢?我們不但要照顧人的眼睛,還要顧及一下顯示器的顯示速度與瀏覽器的渲染速度。根據外國的統計,25毫秒為***數值。其實,這個數值我們應該當作常識來記住。聯想一下,日本動畫好像有個規定是1秒30張畫,中國的,比較垃圾,是1秒24張。用1秒去除以張數,就得到每張停留的時間。日本的那個27.77毫秒已經很接近我們的25毫秒了,因為瀏覽器的渲染速度明顯不如電視機的渲染速度,尤其是IE6這個拉后腿的。要實現加速度,就是讓它每次移動快一點點,讓上一次移動的距離乘以一個大于1的數便可。
01.
//輔助函數3,相當于$(),不用$符號命名是因為博客園在用JQuery,會引起命名沖突
02.
//我新一代查代元素的方法,擁有緩存能力
03.
var
cache = []
04.
var
_ =
function
(id){
05.
return
cache[id] || (cache[id] = document.getElementById(id));
06.
}
07.
//主函數:加速移動
08.
var
accelerate=
function
(el){
09.
el.style.position =
"absolute"
;
10.
var
begin = getCoords(el).left,
11.
distance = parseFloat(getStyle(_(
"taxiway"
),
"width"
)) - parseFloat(getStyle(el,
"width"
)),
12.
end = begin + distance,
13.
speed = 10;
//***次移動的速度,單位px/ms,隱式地乘以1ms
14.
(
function
(){
15.
setTimeout(
function
(){
16.
el.style.left = getCoords(el).left + speed +
"px"
;
//移動
17.
speed *= 1.5;
//下一次移動的距離
18.
if
(getCoords(el).left >= end){
19.
el.style.left = end +
"px"
;
20.
}
else
{
21.
setTimeout(arguments.callee,25);
//每移動一次停留25毫秒
22.
}
23.
},25)
24.
})()
25.
}
明白了加速,減速就好辦了。我們給***次移動的距離一個很大的數,往后每次減少一點點,換言之乘以一個小于1的數。但這里有個注意點,如果有一次,它移動的距離少于1px怎么辦?!它再往后也是少于1px。瀏覽器就會忽略這個值,當作0來處理。這樣一來,它就會停在中途不動了。為了防止這樣可怕的事發生,我們利用Math.ceil來確保其最小移動距離為1px,哪怕***的勻速移動也要抵達終點。
01.
//主函數:減速移動
02.
var
decelerate =
function
(el){
03.
el.style.position =
"absolute"
;
04.
var
begin = getCoords(el).left,
05.
distance = parseFloat(getStyle(_(
"taxiway"
),
"width"
)) - parseFloat(getStyle(el,
"width"
)),
06.
end = begin + distance,
07.
speed = 100;
//***次移動的速度,單位px/ms,隱式地乘以1ms
08.
(
function
(){
09.
setTimeout(
function
(){
10.
el.style.left = getCoords(el).left + speed +
"px"
;
//移動
11.
speed = Math.ceil(speed * 0.9);
//下一次移動的距離
12.
if
(getCoords(el).left <= end){
13.
el.style.left = end +
"px"
;
14.
}
else
{
15.
setTimeout(arguments.callee,25);
16.
}
17.
},25)
18.
})()
19.
}
現在函數的功能還很弱,主要是由于在抽象與制定上有所欠缺,如果克服這些缺點并配合Robert Penner大神的緩動公式,我們就可以搞出花樣繁多的緩動效果來。
原文標題:由淺入深javascript的緩動效果
鏈接:http://www.cnblogs.com/rubylouvre/archive/2009/09/16/1566699.html
【編輯推薦】
- JSON是什么?為JavaScript準備的數據格式
- 十個最常用的JavaScript自定義函數
- 有關JavaScript事件加載的一些延伸思考
- JavaScript使用心得匯總:從BOM和DOM談起
- ExtJS在Android模擬器上的運行效果