DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> JS教程:Javascript實現緩動效果
JS教程:Javascript實現緩動效果
編輯:關於JavaScript     

網頁制作poluoluo文章簡介:緩動,學名為Tween,緩沖移動的簡稱。要想頁面內容切換起來舒服,就使用淡入淡出特效,要想讓頁面元素動起來自然,就要使用緩動效果。這兩個混合起來,可以衍生多種特效的。

緩動,學名為Tween,緩沖移動的簡稱。要想頁面內容切換起來舒服,就使用淡入淡出特效,要想讓頁面元素動起來自然,就要使用緩動效果。這兩個混合起來,可以衍生多種特效的。感謝Flash開發人員為我們做了那麼多先行研究,我們直接把它們拆出來裝在各種菜單與相冊中。我們先從最簡單的東西做起,加速與減速。

既然是緩動,它就一定涉及以下概念:距離,時間與速度。我們可以想象存在一條直線L,點A與點B就是L的起點與終點,有一個點C在直線L上移動,從點A到點B。所需的時間通常都是未知,但速度我們一定要制定。看下面的圖,我們想讓綠色的方塊在淡緊色的滑動帶上移動。滑動帶左上角就相當於點A,右上角就相當於B點,方塊的左上角就相當於點C,移動距離為兩者的寬度之差。由於我們移動的物體是存在寬度,也就是說點C永遠不可能與點B重合。但一個准確的目的地(為了方便,我們把它稱之為點D)是必須的,我們一定要計算它出來。因為在加速運動中,點C隨時可能超過點D,當點超過它時,我們就要終止此移動,並把點C拉回到點D上。

運行代碼框

[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]

為了獲取它們在頁面上的坐標與尺寸,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) 
  }
}

網頁制作poluoluo文章簡介:緩動,學名為Tween,緩沖移動的簡稱。要想頁面內容切換起來舒服,就使用淡入淡出特效,要想讓頁面元素動起來自然,就要使用緩動效果。這兩個混合起來,可以衍生多種特效的。

那麼我們怎麼移動呢?在javascript只有讓它變為絕對定位對象,給它的top與left賦值。它就會立即移動到相應的坐標上。由於javascript處理位置變化太有效率,根本不可能讓你有“移動”的感覺,感覺是直接從點C直接跳到點D。我們必須讓物體每移動一點點,就停一下,讓眼睛有個殘影。根據人眼睛的視覺停留效應,若前一幅畫像留在大腦中的印象還沒消失,後一幅畫像就接踵而至,而且兩副畫面間的差別很小,就會有“動”的感覺。那麼停留多麼毫秒最合適呢?我們不但要照顧人的眼睛,還要顧及一下顯示器的顯示速度與浏覽器的渲染速度。根據外國的統計,25毫秒為最佳數值。其實,這個數值我們應該當作常識來記住。聯想一下,日本動畫好像有個規定是1秒30張畫,中國的,比較垃圾,是1秒24張。用1秒去除以張數,就得到每張停留的時間。日本的那個27.77毫秒已經很接近我們的25毫秒了,因為浏覽器的渲染速度明顯不如電視機的渲染速度,尤其是IE6這個拉後腿的。要實現加速度,就是讓它每次移動快一點點,讓上一次移動的距離乘以一個大於1的數便可。

//輔助函數3,相當於$(),不用$符號命名是因為博客園在用JQuery,會引起命名沖突
//我新一代查代元素的方法,擁有緩存能力
var cache = []
var _ = function(id){ 
  return cache[id] || (cache[id] = document.getElementById(id));
}
//主函數:加速移動
var accelerate= 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 
  (function(){ 
    setTimeout(function(){ 
      el.style.left = getCoords(el).left + speed + "px";//移動 
      speed *= 1.5;//下一次移動的距離 
      if(getCoords(el).left >= end){ 
        el.style.left = end + "px"; 
      }else{        
        setTimeout(arguments.callee,25);//每移動一次停留25毫秒 
      } 
    },25) 
  })()
}

明白了加速,減速就好辦了。我們給第一次移動的距離一個很大的數,往後每次減少一點點,換言之乘以一個小於1的數。但這裡有個注意點,如果有一次,它移動的距離少於1px怎麼辦?!它再往後也是少於1px。浏覽器就會忽略這個值,當作0來處理。這樣一來,它就會停在中途不動了。為了防止這樣可怕的事發生,我們利用Math.ceil來確保其最小移動距離為1px,哪怕最後的勻速移動也要抵達終點。

//主函數:減速移動 
var decelerate = function(el){ 
   el.style.position = "absolute"; 
   var begin =  getCoords(el).left, 
   distance = parseFloat(getStyle(_("taxiway"),"width")) - parseFloat(getStyle(el,"width")), 
   end = begin + distance, 
   speed = 100;//第一次移動的速度,單位px/ms,隱式地乘以1ms 
   (function(){ 
     setTimeout(function(){ 
       el.style.left = getCoords(el).left + speed + "px";//移動 
       speed = Math.ceil(speed * 0.9);//下一次移動的距離 
       if(getCoords(el).left <= end){ 
         el.style.left = end + "px"; 
       }else{        
         setTimeout(arguments.callee,25); 
       } 
     },25) 
   })() 
}

現在函數的功能還很弱,主要是由於在抽象與制定上有所欠缺,如果克服這些缺點並配合Robert Penner大神的緩動公式,我們就可以搞出花樣繁多的緩動效果來。而這正是下面要講解的。

網頁制作poluoluo文章簡介:緩動,學名為Tween,緩沖移動的簡稱。要想頁面內容切換起來舒服,就使用淡入淡出特效,要想讓頁面元素動起來自然,就要使用緩動效果。這兩個混合起來,可以衍生多種特效的。

 

下面這部分對原先的緩動函數進行抽象化,並結合緩動公式進行強化。成品的效果非常驚人逆天。走過路過不要錯過。

好了,打诨到此為止。普通的加速減速是難以讓人滿意的,為了實現彈簧等讓人眼花缭亂的效果必須動用緩動公式。我見過兩套緩動公式,一套是早期Robert Penner大神的緩動公式,內置到tween類中,不過現在人們越來越推薦tweenlite這個新秀了。另一套是script.aculo.us與mootools裡面的,由於mootools可稱之為prototype的升級版,script.aculo.us則是基於prototype,我們就把它們並稱為prototype流派。與flash流派最大的不同是,它們封裝得更好,並只需傳入一個參數(0~1的小數),並且擁有嚴密的隊列機制來調用各種回調函數。如在回調函數設置元素的長寬,就弄成Scale特效,利用它我們進一步制作SlideUp,SlideDown,Squish等復合特效。

我們先來看flash流派的緩動公式,它們基本都有如下四個參數。

  • t:timestamp,指緩動效果開始執行到當前幀開始執行時經過的時間段,單位ms
  • b:beginning position,起始位置
  • c:change,要移動的距離,就是終點位置減去起始位置。
  • d: duration ,緩和效果持續的時間。

我們把這四個參數傳入Robert Penner大神的緩動公式,它就會計算出當前幀物體移動的位置。我們對比原來的函數來改寫。

var transition = function(el){ 
  transition.linear = function(t,b,c,d){ return c*t/d + b; };//免費提供一個緩動公式(勻速運動公式) 
  el.style.position = "absolute"; 
  var options = arguments[1] || {}, 
  begin =  getCoords(el).left,//開始位置 
  change = parseFloat(getStyle(_("taxiway"),"width")) - parseFloat(getStyle(el,"width")),//要移動的距離 
  duration = options.duration || 500,//緩動效果持續時間 
  ease = options.ease || transition.linear,//要使用的緩動公式 
  end = begin + change,//結束位置 
  startTime = new Date().getTime();//開始執行的時間 
  (function(){ 
    setTimeout(function(){ 
      var newTime = new Date().getTime(),//當前幀開始的時間 
      timestamp = newTime - startTime;//逝去時間 
      el.style.left = ease(timestamp,begin,change,duration) + "px";//移動 
      if(duration <= timestamp){ 
        el.style.left = end + "px"; 
      }else{ 
        setTimeout(arguments.callee,25);//每移動一次停留25毫秒 
      } 
    },25) 
  })()
}

接著是各種緩動公式大閱兵,共分為十一大類,除了linear。其他類又分為三種。

  1. easeIn方法控制補間如何從開始到最高速度。
  2. easeOut 方法控制補間減速並停在目標位置
  3. easeInOut方法同時控制上述兩者。

具體公式見下面(共31種):

代碼拷貝框

[Ctrl+A 全部選擇 然後拷貝]

<div id="taxiway">  
<div id="move" onclick="transition(this,{ease:Tween.Bounce.easeOut})"></div>
</div>

網頁制作poluoluo文章簡介:緩動,學名為Tween,緩沖移動的簡稱。要想頁面內容切換起來舒服,就使用淡入淡出特效,要想讓頁面元素動起來自然,就要使用緩動效果。這兩個混合起來,可以衍生多種特效的。

 

但我不喜歡flash流派的緩動公式,為了使用prototype流派的緩動公式,我進一步改進與抽象化我的緩動函數

//******************@author : 司徒正美************ 
  var transition = function(el){ 
    el.style.position = "absolute"; 
    var options = arguments[1] || {}, 
    begin =  options.begin,//開始位置 
    change = options.change,//變化量 
    duration = options.duration || 500,//緩動效果持續時間 
    field = options.field,//必須指定,基本上對top,left,width,height這個屬性進行設置 
    ftp = options.ftp || 50, 
    onStart = options.onStart || function(){}, 
    onEnd = options.onEnd || function(){}, 
    ease = options.ease,//要使用的緩動公式 
    end = begin + change,//結束位置 
    startTime = new Date().getTime();//開始執行的時間 
    onStart(); 
    (function(){ 
      setTimeout(function(){ 
        var newTime = new Date().getTime(),//當前幀開始的時間 
        timestamp = newTime - startTime,//逝去時間 
        delta = ease(timestamp / duration); 
        el.style[field] = Math.ceil(begin + delta * change) + "px"
        if(duration <= timestamp){ 
          el.style[field] = end + "px"; 
          onEnd(); 
        }else{ 
          setTimeout(arguments.callee,1000/ftp); 
        } 
      },1000/ftp) 
    })() 
  }

參數 類型 說明 el element 必需,為頁面元素 begin number 必需,開始的位置 change number 必需,要移動的距離 duration number 可選,緩動效果持續時間,默認是500ms。建議取300~1000ms。 field string 必需,要發生變化的樣式屬性。請在top,left,bottom,right,width與height中選擇。 ftp number 可選,每秒進行多少幀動畫,默認50幀,保證流暢播放。一些參考資料,日本動畫1秒36幀,中國卡通24幀,賽車游戲60幀。 ease function 必需,緩動公式,參數為0~1之間的數。可參考我下面給出的45條公式。 onStart function 可選,在開始時執行。 onEnd function 可選,在結束時執行。

prototype流派的緩動公式,只需一個參數(增至45種):

代碼拷貝框

[Ctrl+A 全部選擇 然後拷貝]

運行代碼框

[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]

除了這45條公式外,我們還可以制定自己的緩動公式。正如我在上面表格中提到,它在運行過程是不執行回調函數時,但你們可以在運行框中看到,我可以實現一邊移動一邊記錄點的坐標。這是怎樣實現的呢?我們只要把上面的緩動公式的任何一條塞進一個只有一個參數的函數就行了。當然此函數要有返回,供繼續向下調用。以下就是一個模板:

var myTween = function(pos){ //緩動公式 
    var value = tween[ease](pos); 
    //***********這上面是固定的************** 
    indicator.style.display = "block"; 
    marker.style.display = "block"; 
    marker.style.left = Math.round((pos*200))+'px'; 
    marker.style.bottom = Math.round(((value*200)-min)*factor)+'px'; 
    label.innerHTML = Math.round((pos*200))+'px'; 
    //************這下面是固定的************* 
    return value; 
  }

更多示例,不懂再留言給我。

<div class="taxiway"> 
  <div class="move" onclick="transition(this,{field:'left',begin:parseFloat(getCoords(this).left),change:700,ease:tween.bouncePast})"></div>
</div>
<div class="taxiway"> 
  <div class="move" onclick="transition(this,{field:'width',begin:parseFloat(getStyle(this,'width')),change:300,ease:tween.spring})"></div>
</div>

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved