這段時間身體欠佳,經常頭暈。醫生說并無大礙,可我服了藥也不見有多少好轉。因此我很久沒有更新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 閱讀(5634)
評論(6) 編輯 收藏 所屬分類:
方法與技巧(Tips & tricks)