一、 简介
    在探讨微软ASP.NET Ajax框架的过程中,我总结出这个框架在网页动画方面的支持可分为以下两种类型:第一部分是依托于Futures CTP部分的跨浏览器兼容的低级动画技术;第二部分是依赖于ASP.NET 2.0服务器端技术的ASP.NET AJAX Control Toolkit部分。很明显,这两种方案各存利弊。在本文中,我将专注于向读者介绍第一种方案,即“跨浏览器兼容的低级动画技术”,并针对每种动画给出相应的示例网页程序。

【注】本文示例程序试验环境为:Windows XP Professional+IIS 6.0+Visual Studio 2005+ASP.NET AJAX框架的前两部分(即ASP.NET AJAX Essential Components和ASP.NET AJAX Futures May CTP),而第三部分ASP.NET AJAX Control Toolkit是可选安装的;但本文强烈建议读者试安装之,因为这一部分中包含了前面提到的完整的第二种方案动画技术。
二、 网页动画概述
    网页中的动画是我们司空见惯的,合理地在页面中运用动画效果可以给用户以相当震撼的视觉冲击,并牢牢地抓住用户的眼球。在网页中实现动画的方式多种多样,Flash就是其中的佼佼者。对于大型网页动画设计而言,Flash应是首当其冲的选择工具;但对于普通开发中某些常见的、小巧的动画效果,例如删除列表某一行之后该行以淡出的效果消失等,使用Flash则犹如杀鸡用宰牛刀—笨得很。

    针对这种情形,ASP.NET AJAX也当仁不让,在其Futures CTP部分中提供了许多种内置的动画技术支持。所有这些动画都定义于一个叫PreviewGlitz.js的文件内(此文件内置于Futures CTP程序集Microsoft.Web.Preview.dll中)。
为了更为清晰地区别本文中我们所学习的各种动画间的关系,下图1是我从脚本文件PreviewGlitz.js中提取出的各种动画类间的继承关系图。 
   

        图1—Futures CTP提供的各种动画类间的继承关系图。

    从上图中看出,Animation是所有MS AJAX客户端动画类的基类。尽管PropertyAnimation和InterpolatedAnimation这两个类也是派生自Animation类的子类,但一般情况下,它们仍作为基类进一步派生子类使用而不单独用于创建动画。
三、 创建淡入/淡出动画效果
    借助于FadeAnimation动画类,我们可以实现使页面中的某个层的不透明度逐渐变为1(淡入)或变为0(淡出)。
请启动Visual Studio 2005,然后选择菜单项“文件|新建网站…”,使用模板“ASP.NET AJAX CTP-Enabled网站”创建一个新的网站,并命名工程为GlitzTest(选择Visual C#作为内置语言)。此后,系统应该自动地添加对必要的程序集—System.Web.Extension.dll(你无法直接在bin目录下看到它)和Microsoft.Web.Preview.dll的参考。

    此外,你会注意到一个ScriptManager服务器控件自动地添加到页面中。注意,这个服务器控件作为整个ASP.NET AJAX框架的控制中心。

    【注意】由于本文中的动画类都存在于一个外部库中,所以,我们必须以手工方式把文件PreviewGlitz.js包含到任何使用它们的网页的控件的子节下面。此外,我们还要以同样方式手工包含文件—PreviewScript.js(这个文件是整个Futures CTP的核心)。此外,为了简单起见,我把本文中所有示例页面纳入到一个示例工程GlitzTest下。
然后,右击工程GlitzTest添加一个新网页并命名为AjaxFadeAnimation.aspx。稍试修改,你会得到如下面图2所示的设计时刻快照。 
   

    图2—淡入/淡出动画演示网页设计时刻快照。
下面,首先让我们来看这个网页相应的HTML代码部分。 
    
    
    
    









Fading in and out Animation Demo









    首先,关于节中的内容前面已经提过。接下来,我们定义了两个按钮(相应的id值分别为btnFadeOutAnimate和btnFadeInAnimate),并且分别把它们与自己的onclick事件处理器关联起来。后面跟着的是一个标签,用于测试淡入/淡出效果之用。读者可能已经猜出其中的关键在于这两个事件处理器函数。不错!下面就让我们对其进行深入的分析。 
   
 
    
    在这段代码中,我们首先获取一个到动画目标的句柄(或指针)。然后,创建动画类FadeAnimation的一个实例fadeAnimation。然后,设置这个实例的相应的常用动画参数,例如持续时间,这个动画实例针对的目标对象,最大不透明度,播放速率(帧/秒)等。至此,我们为动画播放作好了全面的准备。然后,当用户点击按钮“Fade Out”(或“Fade In”)时,事件处理器函数FadeUsingFutures被激发,根据传入参数确定播放类型,最后正式进行动画播放。
四、 创建长度动画效果
    接下来,我们来学习另一种类型的动画—LengthAnimation。这种动画可以用来在某个开始和结束的范围内连续地改变某个属性值。这种动画的典型应用就是逐渐改变某个控件的长度和宽度属性值。

    注意,虽然这种LengthAnimation动画用来改变某个数值类型的属性值十分容易,只需要指定某开始值和结束值即可,但它也同样可以用来连续地改变文本类型的属性值。

    为了进一步了解这种动画的实现细节,下面表格列举了这种动画的一些常用的属性。  
属性
描述
target
指定页面上将要应用该动画的元素的id
property
指定该动画将应用到页面元素中的哪个属性上
startValue
指定该动画将改变的值范围的开始值
endValue
指定该动画将改变的值范围的结束值
unit
指定该动画将改变的属性的单位。例如像素单位使用px,百分比单位使用%
duration
指定该动画将运行的时间长度,单位为秒
fps
获取或设置该动画的fps属性。默认值为25
isActive
获取一个布尔值,代表该动画是否已经开始运行
isPlaying
获取一个布尔值,代表该动画是否正在运行
percentComplete
获取一上0到100的数字,代表该动画目前完成运行的百分比
    表格1—动画LengthAnimation常用属性。
    
    下面,让我们来创建一个简单的长度动画。
如上面一样,仍然是右击工程GlitzTest添加一个新网页并命名为LengthAnimation.aspx。稍加修改,你会得到如下面图3所示的设计时刻快照。 
   

    图3—长度动画演示网页设计时刻快照。

  下面的图4则展示了动画过程中的某一时刻的屏幕快照。 
   

    图4—长度动画演示过程中某一时刻的屏幕快照。
你可能已经猜出,动画的最后结果将显示一张最大的图片。
下面,让我们深入分析其中的逻辑。下面是代码相应于页面LengthAnimation.aspx的HTML代码部分。
//……省略




注意,在此我们首先使用标签创建了一幅图画,并直接指定其初始宽度值为100,而不是使用style属性指定其宽度值—这对于后面将改变我们的动画目标的属性width而言是极其重要的。后面的按钮定义不再赘述。
接下来,让我们分析真正吸引我们的相关xml-script编程部分,如下所示:
   
     
     
     
     

    在此,我们首先使用标签创建了一个Sys.Preview.UI.Image的实例(使其指向id为i的实际的HTML元素)。然后,我们定义了一个LayoutBehavior(其id为“Label1Style”),并把它绑定到上面的图像实例上。注意,这个LayoutBehavior行为将用作后面定义的LengthAnimation动画的目标。通过连续地改变行为Label1Style的宽度(从100px改变到480px),使图像的尺寸发生相应的改变。注意,在此将属性duration的值设置得越小,图像变大的速度将越快。此外,如果把属性startValue的值设置得比endValue的值还大,则LengthAnimation动画将以相反的方向执行,即从属性startValue减小到endValue,表现为图像由原来的较大变得逐渐收缩。

    【注】本人在实验中发现一件奇怪的事情:在上面的编程中,如果我们不引入行为LayoutBehavior作为“中介”,在点击按钮Start时只能导致屏幕上的图片一下子消失。这是否是一个“bug”?对于动画LengthAnimation而言,目前实在没有太多的参考资料,只能靠我们自己试验,试验,再试验……
五、 创建数字动画效果
     这个NumberAnimation动画的特征十分类似于LengthAnimation(具有相同的属性,例如target,property,startValue,endValue,duration,fps,isActive,isPlaying,percentComplete,等等);不过,也存在两处重要的区别。其一是,动画NumberAnimation的中间值在改变时可以带有小数(通过属性integralValues来设置实现)。于是,在某些特定场合下(例如对于长度单位米的处理),使用动画NumberAnimation将会带来更好的效果。第二个区别在于,动画LengthAnimation支持基于像素的动画的改变(通过属性unit来实现),而动画NumberAnimation却不是这样。
现在,让我们来看一个模拟倒计时的直观的例子。

    仍然使用鼠标右键单击工程GlitzTest并且添加一个新的网页,并命名为NumberAnimation2.aspx(注意,在本文示例工程GlitzTest中,我还提供了另一个展示动画NumberAnimation功能的例子—对应网页NumberAnimation.aspx。此动画的目标是通过逐渐改变行为OpacityBehavior的属性值来模拟淡入/淡出动画效果。具体实现请参考下载源码)。下列的图5展示了页面NumberAnimation2.aspx的设计时刻屏幕快照。 
   

    图5—数字动画演示网页设计时刻快照。

    在最开始,一个整数30显示于屏幕之上。随着把属性integralValues设置为false和动画过程的不断进行,屏幕上逐渐出现如图6所示的小数的情形。 
   

    图6—倒计时过程中屏幕出现小数的情形。
在这个例子中,我们在屏幕上放置了一个元素用于表现要倒计时的内容,还有一个按钮来触发该动画过程。篇幅所限,我们仍然只讨论如下所示的xml-script编程部分:
     
     
     
     


//……省略


 
    在上面的脚本中,我们首先把一个名字为mynumber的元素与一个MS AJAX客户端Label控件关联起来。注意,在此控件Label提供了一个名为text的属性,这个属性值的改变将显示于对应的元素内。接下来,创建了一个名为numberAnimation的结点—其属性target指向标签mynumber,property设置为text,从而使动画的内容在控件mynumber中得以改变。然后,我们分别把两个相关的属性startValue和endValue设置为30和0。通过把属性integralValues的值设置为false,网页才能显示出小数部分;否则(设置为true的话),我们将看到一个倒计时的秒表效果的动画。

    总的来说,借助于动画NumberAnimation,我们可以非常容易地连续不断地改变某个值,并把这一过程与页面中的某个元素关联起来。
六、 创建离散动画效果
    现在,让我们讨论另外一种类型的动画—DiscreteAnimation。首先,在这种动画与前面讨论的两种动画LengthAnimation和NumberAnimation之间依然存在某些相似性,例如同样可以在某个特定的时间内依次给出某个范围内的值。不过,对于动画LengthAnimation和NumberAnimation而言,只需给出开始值和结束值即可,由MS AJAX框架负责计算所有的中间值。但对于离散动画而言,我们必须给出动画过程中的所有中间值,例如26个英文字母的列表或一串单词的列表等。然后,在动画播放过程中,由DiscreteAnimation实时地播放出这个序列中的每一个值。这种动画也支持例如target,property,duration,fps,isActive,isPlaying,percentComplete等属性,但还提供了一个特有的属性—values。这个values属性用于指定动画过程中的所有中间值,并用逗号将所有可选值连接起来,组成一个字符串。

    下面,让我们创建一个利用离散技术创建动画效果的例子。仍然使用鼠标右键单击工程GlitzTest并且添加一个新的网页,并命名为discrete.aspx。下列的图7展示了示例页面的设计时刻屏幕快照。 
   

    图7—离散动画演示网页设计时刻快照。

    如果你按下F5运行这个例子,那么,你将看到一个离散动画过程:屏幕中的文本标签内容依次从“Sunday”改变到“Saturday”。在此,我们依然只讨论相应的xml-script编码部分。
     
     
     
     
 
     
       在上面的脚本中,我们首先把一个名为sampleLabel的元素与一个MS AJAX客户端Label控件建立关联(此控件将对应离散动画的目标元素)。然后,创建了一个名为discreteAnimation的结点,其属性target指向标签sampleLabel,属性property指向控件sampleLabel的text属性。当然,这里最重要的属性还是values,它的值是一个由多个可选元素组成并以逗号间隔的字符串。读者应该猜出,如果我们在此指定一串整数,则完全可以模拟一个倒计时秒表的效果。仅此而已。