这段时间身体欠佳,经常头晕。医生说并无大碍,可我服了药也不见有多少好转。因此我很久没有更新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 阅读(5624)
评论(6) 编辑 收藏 所属分类:
方法与技巧(Tips & tricks)