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