緩動,學名為Tween,緩衝移動的簡稱。想頁面內容切換起來舒服,就使用淡入淡出特效,要讓頁面元素動起來自然,就要使用緩動效果。這兩個混合起來,可以衍生多種特效的。感謝Flash開發人員為我們做了這麼多先行研究,我們直接把它們拆出來裝在各種菜單與相簿中。我們先從最簡單的東西做起,加速減速。
既然是緩動,它就一定涉及以下概念:距離,時間與速度。我們可以想像存在一條直線L,點A與點B就是L的起點與終點,有點C在直線L上移動,從點A到點B。所需的時間通常都是未知,但速度我們一定要訂定。看下面的圖,我們想讓綠色的方塊在淡緊色的滑動帶上移動。滑動帶左上角相當於點A,右上角就相當於B點,方塊的左上角就相當於點C,移動距離為兩者的寬度之差。由於我們移動的物體是存在寬度,也就是說點C永遠不可能與點B重合。但一個準確的目的地(為了方便,我們把它稱之為點D)是必須的,我們一定要計算它出來。因為在加速運動中,點C隨時可能超過點D,當點超過它時,我們就要終止此移動,並把點C拉回到點D上。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
</HEAD>
<BODY>
<STYLE type=text/css>#taxiway {
BACKGROUND: #e8e8ff; WIDTH: 800px; HEIGHT: 100px
}
#move {
BACKGROUND: #a9ea00; WIDTH: 100px; HEIGHT: 100px
}
</STYLE>
<DIV id=taxiway>
<DIV id=move onclick=move(this)></DIV></DIV>
<P class=notice display="text-align:center">點選可移動綠色方塊</P>
<SCRIPT type=text/javascript>
var getCoords = function(el){
var box = el.getBoundingClientRect(),
doc = el.ownerDocument,
body = doc.body,
html = doc.documentElement,
clientTop = html.clientTop || body.clientTop || 0,
clientLeft = html.clientLeft || body.clientLeft || 0,
top = box.top + (self.pageYOffset || html.scrollTop || body.scrollTop ) - clientTop,
left = box.left + (self.pageXOffset || html.scrollLeft || body.scrollLeft) - clientLeft
return { 'top': top, 'left': left };
};
var getStyle = function(el, style){
if(!+"v1"){
style = style.replace(/-(w)/g, function(all, letter){
return letter.toUpperCase();
});
var value = el.currentStyle[style];
(value == "auto")&&(value = "0px" );
return value;
}else{
return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
}
}
//輔助函數3,相當於$(),不用$符號命名是因為部落格園在用JQuery,會造成命名衝突
//我新一代查代元素的方法,擁有快取能力
var cache = []
var _ = function(id){
return cache[id] || (cache[id] = document.getElementById(id));
}
var move = function(el){
el.style.position = "absolute";
var begin = getCoords(el).left,
distance = parseFloat(getStyle(_("taxiway"),"width")) - parseFloat(getStyle(el,"width")),
end = begin + distance,
speed = 10,//第一次移動的速度,單位px/ms,隱式地乘以1ms
delta = 1.5,
change = true;
el.onclick = function(){
if(change){
el.innerHTML = "加速";
(function(){
setTimeout(function(){
el.style.left = getCoords(el).left + speed + "px";//移動
speed *= delta;//下次移動的距離
if(getCoords(el).left >= end){
el.style.left = end + "px";
change = false;
delta = 0.85,
speed = 100;
}else{
setTimeout(arguments.callee,25);//每移動一次停留25毫秒
}
},25)
})()
}else{
el.innerHTML = "減速";
(function(){
setTimeout(function(){
el.style.left = getCoords(el).left - speed + "px";//移動
speed = Math.ceil(speed * delta );//下次移動的距離
if(getCoords(el).left <= begin ){
el.style.left = begin + "px";
change = true;
delta = 1.5,
speed = 10;
}else{
setTimeout(arguments.callee,25);
}
},25)
})()
}
}
}
window.onload = function(){
move(_("move"))
}
</SCRIPT>
</BODY></HTML>
為了取得它們在頁面上的座標與尺寸,getCoords()與getStyle()又到出場時間了。對不起,我實在沒有意思來炫耀我的函數。更何況getStyle()被砍去了不少東西,威力沒有以前那麼強大。
//輔助函數1
var getCoords = function(el){
var box = el.getBoundingClientRect(),
doc = el.ownerDocument,
body = doc.body,
html = doc.documentElement,
clientTop = html.clientTop || body.clientTop || 0,
clientLeft = html.clientLeft || body.clientLeft || 0,
top = box.top + (self.pageYOffset || html.scrollTop || body.scrollTop ) - clientTop,
left = box.left + (self.pageXOffset || html.scrollLeft || body.scrollLeft) - clientLeft
return { 'top': top, 'left': left };
};
//輔助函數2
var getStyle = function(el, style){
if(!+"v1"){
style = style.replace(/-(w)/g, function(all, letter){
return letter.toUpperCase();
});
var value = el.currentStyle[style];
(value == "auto")&&(value = "0px" );
return value;
}else{
return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
}
}