這段時間身體欠佳,經常頭暈。醫生說并無大礙,可我服了藥也不見有多少好轉。因此我很久沒有更新Blog了。
針對大家關于Struts 2的問題,我正著手開發一個應用程序例子。這個例子以ASP.NET的“Personal Web Site Stater Kit”應用程序作為藍本,采用“Spring 2 + Hiberante 3 + Struct 2”架構(姑且稱之:-)),并且會以“prototype+DWR”為基礎實現AJAX。
在AJAX如火如荼的今天,相信大家對Prototype這個Javascript類庫應該都有所耳聞,它也的確使編寫Javascript變得更簡單。關于Prototype的文章,《Prototype簡介》、《Prototype源碼》諸如此類數不勝數;所以本文不會再做這幾方面的介紹,并假設讀者對Prototype有一定了解。
網頁動畫與原理
提到網頁動畫,大家首先想起應該Flash。不知道大家沒有開發過Flash動畫,故我想對此作一個簡單的介紹(在我讀大學的時候,對Flash也曾有過癡迷,所以也略懂一二)。Flash的動畫主要分兩類:漸變動畫和逐幀動畫。
- 漸類動畫——用戶在時間軸上創建開始的關鍵幀和結束的關鍵幀,開發環境(Macromedia Profassional Flash 8等)會根據以上所創建的關鍵幀的顏色、位置和形狀等,在計算出中間的過渡幀并添加到相應的時間軸上。這適用于創建簡單的動畫。
- 逐幀動畫——用戶在時間軸的每幀上創建關鍵幀,并在其中繪制相應的圖按。這適用于創建復雜的動畫。
在Javascript中由于沒有繪圖API(應用程序接口),故只可以使用DOM+CSS改變元素的外觀。而通過每隔一段時間調用一次改變元素外觀的函數,實現類似Flash的漸類動畫。
具體實現
因為不同的Javascript動畫實現的基本原理都相同,所以可以創建一個基類將其抽象出來。代碼如下:
var Animation = Class.create();

Animation.prototype =
{

/**/ /* ------------------------------------------------------------------------
| 用途:
| 構造函數
|
| 參數:
| element 將要實現動畫效果的元素
| fps 每秒播放幀數
------------------------------------------------------------------------ */

initialize: function (element, fps)
{
this .element = $(element);
this .interval = Math.round( 1000 / fps);
this .isPlaying = false ;
this .currentFrame = 1 ;
// 創建一個用于存儲中間狀態的臨時對象
this .temp =
{ } ;
} ,

/**/ /* ------------------------------------------------------------------------
| 用途:
| 子類覆蓋該方法,實現自定義的動畫補間
------------------------------------------------------------------------ */

_createTweens: function (original, transformed, frames)
{ } ,

/**/ /* ------------------------------------------------------------------------
| 用途:
| 創建動畫補間
|
| 參數:
| original 開始狀態
| transformed 結束狀態
| frames 動畫幀數
------------------------------------------------------------------------ */

createTweens: function (original, transformed, frames)
{

if ( this .isPlaying)
{
this .stop();
}
this ._createTweens(original, transformed, frames);
this .original = original;
this .transformed = transformed;
this .frames = frames;
// 將開始狀態拷貝到臨時對象
Object.extend( this .temp, original);
} ,

/**/ /* ------------------------------------------------------------------------
| 用途:
| 判斷臨時對象狀態是否超出結束狀態
|
| 參數:
| prop 狀態屬性名稱
------------------------------------------------------------------------ */

_isOverstep: function (prop)
{

if ( this .original[prop] < this .transformed[prop])
{
return this .temp[prop] > this .transformed[prop];
}
return this .temp[prop] < this .transformed[prop];
} ,

_prepare: function ()
{ } ,

_draw: function (frame)
{ } ,

_drawFrame: function ()
{

if ( this .isPlaying)
{

if ( this .currentFrame < this .frames)
{
this ._prepare();
this ._draw( this .temp);
this .currentFrame ++ ;

} else
{
// 最后一幀繪制結束狀態
this ._draw( this .transformed);
this .stop();
}
}
} ,

_play: function ()
{ } ,

play: function ()
{

if ( ! this .isPlaying)
{
this ._play();
this .isPlaying = true ;
this .timer = setInterval( this ._drawFrame.bind( this ), this .interval);
}
} ,

_stop: function ()
{ } ,

stop: function ()
{

if ( this .isPlaying)
{
this ._stop();
// 回到開始狀態
this .isPlaying = false ;
this .currentFrame = 1 ;
Object.extend( this .temp, this .original);
clearInterval( this .timer);
}
} ,

_pause: function ()
{ } ,

pause: function ()
{

if ( this .isPlaying)
{
this ._pause();
this .isPlaying = false ;
clearInterval( this .timer);
}
}
}
清單1 Animation.js
Animation類實現了一些公用的管理內部狀態的操作,如播放動畫、停止動畫和暫停動畫等。接下來,創建特定的動畫變得相當容易了,下面讓我們來看一個形狀和位置漸變的動畫實現,代碼如下:
var ShapeAnimation = Class.create();

ShapeAnimation.prototype = Object.extend( new Animation(),
{

/**/ /* ------------------------------------------------------------------------
| 用途:
| 覆蓋父類的空白實現,計算每幀的變化量
------------------------------------------------------------------------ */

_createTweens: function (original, transformed, frames)
{
this .xSpan = Math.round((transformed.x - original.x) / frames);
this .ySpan = Math.round((transformed.y - original.y) / frames);
this .wSpan = Math.round((transformed.w - original.w) / frames);
this .hSpan = Math.round((transformed.h - original.h) / frames);
} ,

/**/ /* ------------------------------------------------------------------------
| 用途:
| 覆蓋父類的空白實現,計算當前的狀態。如果超出結束狀態,保持結束狀態不變
------------------------------------------------------------------------ */
_prepare: function ()
{
this .temp.x = this ._isOverstep('x') ? this .transformed.x : this .temp.x + this .xSpan;
this .temp.y = this ._isOverstep('r') ? this .transformed.y : this .temp.y + this .ySpan;
this .temp.w = this ._isOverstep('w') ? this .transformed.w : this .temp.w + this .wSpan;
this .temp.h = this ._isOverstep('h') ? this .transformed.h : this .temp.h + this .hSpan;
} ,

/**/ /* ------------------------------------------------------------------------
| 用途:
| 覆蓋父類的空白實現,刷新元素外觀
------------------------------------------------------------------------ */
_draw: function (frame)
{
var x = frame.x + 'px';
var y = frame.y + 'px';
var w = frame.w + 'px';
var h = frame.h + 'px';

Element.setStyle( this .element,
{ left: x, top: y, width: w, height: h } );
}
} );
清單2 ShapeAnimation.js
ShapeAnimation類繼承Animation類,并覆蓋了其中的某些方法。最后,讓我們創建HTML文件,測試一下這個ShapeAnimation是否可以正確工作。代碼如下:
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > ShapeAnimation Test </ title >
< script type ="text/javascript" src ="prototype-1.4.0.js" ></ script >
< script type ="text/javascript" src ="Animation.js" ></ script >
< script type ="text/javascript" src ="ShapeAnimation.js" ></ script >
< script type ="text/javascript" >
var animation;
Event.observe(window, 'load', init, false );
function init() {
var clip = $('clip');
var pos = Position.cumulativeOffset(clip);
animation = new ShapeAnimation(clip, 12 );
animation.createTweens( { x: pos[ 0 ], y: pos[ 1 ], w: 100 , h: 75 },
{ x: 100 , y: 100 , w: 200 , h: 200 },
24 );
}
function play() {
animation.play();
}
function stop() {
animation.stop();
}
function pause() {
animation.pause();
}
</ script >
</ head >
< body >
< input type ="button" onclick ="play()" value ="Play" />
< input type ="button" onclick ="stop()" value ="Stop" />
< input type ="button" onclick ="pause()" value ="Pause" />< br />
< br />
< img src ="thumb.jpg" alt ="Thumb" id ="clip" style ="left: 13px; position: absolute; top: 52px;" />
</ body >
</ html >
清單3 ShapeAnimationTest.htm
分別在IE或Firefox中打開ShapeAnimationTest.htm,播擊“Play”、“Stop”和“Pause”按鈕工作正常。
舉一反三
上述例子,我創建了形狀動畫類。有了Animation類作為基類,當然我可以容易地創建更多的動畫類。下面我再舉一個裁剪動畫示例。代碼如下:
var ClipAnimation = Class.create();

ClipAnimation.prototype = Object.extend( new Animation(),
{

_createTweens: function (original, transformed, frames)
{
this .tSpan = Math.round((transformed.t - original.t) / frames);
this .rSpan = Math.round((transformed.r - original.r) / frames);
this .bSpan = Math.round((transformed.b - original.b) / frames);
this .lSpan = Math.round((transformed.l - original.l) / frames);
} ,

_prepare: function ()
{
this .temp.t = this ._isOverstep('t') ? this .transformed.t : this .temp.t + this .tSpan;
this .temp.r = this ._isOverstep('r') ? this .transformed.r : this .temp.r + this .rSpan;
this .temp.b = this ._isOverstep('b') ? this .transformed.b : this .temp.b + this .bSpan;
this .temp.l = this ._isOverstep('l') ? this .transformed.l : this .temp.l + this .lSpan;
} ,

_draw: function (frame)
{
var clipStyle = 'rect(' + frame.t + 'px ';
clipStyle = clipStyle + frame.r + 'px ';
clipStyle = clipStyle + frame.b + 'px ';
clipStyle = clipStyle + frame.l + 'px)';

Element.setStyle( this .element,
{ clip: clipStyle } );
}
} );
清單4 ClipAnimation.js
測試文件代碼如下:
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > Untitled Page </ title >
< script type ="text/javascript" src ="prototype-1.4.0.js" ></ script >
< script type ="text/javascript" src ="Animation.js" ></ script >
< script type ="text/javascript" src ="ClipAnimation.js" ></ script >
< script type ="text/javascript" >
var animation;
Event.observe(window, 'load', init, false );
function init() {
var clip = $('clip');
var pos = Position.cumulativeOffset(clip);
var dimensions = Element.getDimensions(clip);
animation = new ClipAnimation(clip, 12 );
animation.createTweens( { t: 0 , r: dimensions.width, b: Element.getHeight(clip), l: 0 },
{ t: 0 , r: dimensions.width, b: 0 , l: 0 },
24 );
}
function play() {
animation.play();
}
function stop() {
animation.stop();
}
function pause() {
animation.pause();
}
</ script >
</ head >
< body >
< input type ="button" onclick ="play()" value ="Play" />
< input type ="button" onclick ="stop()" value ="Stop" />
< input type ="button" onclick ="pause()" value ="Pause" />< br />
< br />
< img src ="thumb.jpg" alt ="Thumb" id ="clip" style ="left: 13px; position: absolute; top: 52px;" />
</ body >
</ html >
清單5 ClipAnimationTest.htm
總結
Prototype實現了部分的面向對象,對常用的操作提供了方便的封裝。這樣我們可以編寫具有更高可重性的Javascript代碼,將實現重HTML文件中分離出來,使程序結構更清晰可讀。
點擊以下鏈接下載示例代碼
posted on 2007-01-26 15:06
Max 閱讀(970)
評論(2) 編輯 收藏 引用 所屬分類:
方法與技巧(Tips & tricks)