用js实现动画效果的主要思想是利用setInterval()函数.此函数可按照指定的周期(以毫秒计)来调用函数或表达式,并且该方法会不停地调用函数,直到clearInterval()被调用或窗口被关闭。由setInterval()返回的ID值可用作clearInterval()方法的参数。
1.单个元素匀速运动
以匀速水平方向运动的元素为例,该方法传入三个参数,分别为要移动元素,要移动到的目标和移动的速度。其中,若速度大于0,表示元素从左向右移动;若速度小于0,表示元素从右向左移动
function startMove(ele,iTarget,speed){
var timer=null;
clearInterval(timer);//防止方法重复执行时,计时器的重复使用
timer=setInterval(function(){
if(ele.offsetLeft!=iTarget){
ele.style.left=ele.offsetLeft+speed+"px";}
},100);
}
实现当鼠标在元素上移动时,使元素从左向右移动的效果
var move=document.getElementById("move");
move.onmousemove=function(){startMove(move,500,10);}
2.单个元素透明度的匀速变化
设元素的初始透明度为opacity:0.3或filter:alpha(opacity:30),透明度匀速变化的方法如下
function startOpacity(ele,iTarget,speed){实现当鼠标在元素上移动时,使元素透明度从0.3变为1,或从30变为100
var timer=null;
var alpha=30;//元素透明度的值获取较难,这里直接给出
clearInterval(timer);
timer=setInterval(function(){
if(alpha!=iTarget){
alpha+=speed;
ele.style.filter='alpha(opacity:'+alpha+')'; //设置IE的透明度
ele.style.opacity= alpha/100; //设置fierfox等透明度,注意透明度值是小数
}
},50);
}
var move=document.getElementById("move");
move.onmousemove=function(){
startOpacity(move,100,10);}
3.单个元素的缓冲运动
缓冲运动的本质是速度的不断变化,元素运动时越靠近目标其速度越小,实现方法如下
function bufferMove(ele,iTarget){实现当鼠标在元素上移动时,元素做缓冲运动到达目标值
var timer=null;
clearInterval(timer);
timer=setInterval(function(){
var speed=(iTarget-ele.offsetLeft)/200;
if(speed>0){
speed=Math.ceil(speed);//避免速度值出现小数的状况,因为元素有关的像素值必须为整数
speed=Math.floor(speed);
}
if(ele.offsetLeft!=iTarget){
ele.style.left=ele.offsetLeft+speed+"px";}
},100);
}
var move=document.getElementById("move");
move.onmousemove=function(){
bufferMove(move,500);
}
4.多物体的缓冲运动
多物体的运动需要注意的是物体之间公共的变量或计时器,为了防止多物体之间的共用,需要将物体之共用的部分私有化
本例所实现的功能时,当鼠标移动到三个li元素中的一个时,其宽度从200px变为500px,移出时宽度从500px变为200px
var container=document.getElementById("container");
var iLi=container.getElementsByTagName("li");
for(var i=0,length=iLi.length;i<length;i++){
iLi[i].timer=null;//将计时器私有
iLi[i].onmouseover=function(){
bufferMove(this,500);//注意,这里用到了闭包的知识,this并不等于iLi[i],因为变量i即使bufferMove的活动对象,同时也是其父方法的活动对象,二者共用一个内存空间,所以如果在这里用iLi[i],该值就相当于iLi[3]
}
iLi[i].onmouseout=function(){
bufferMove(this,200);
}
}
function bufferMove(ele,iTarget){
clearInterval(ele.timer);
ele.timer=setInterval(function(){
var speed=(iTarget-ele.offsetWidth)/10;
if(speed>0){
speed=Math.ceil(speed);
}else{
speed=Math.floor(speed);
}
if(ele.offsetWidth!=iTarget){
ele.style.width=ele.offsetWidth+speed+"px";}
},100);
}
当li元素中没有边框和内边距样式时,此方法有效,但当含有边框和内边距样式时,由于offsetWidth属性包含元素的宽度、内边距和元素的边框,其运行后的元素宽度和预定的宽度不同,为了解决这个问题,我们需要将offsetWidth属性变改为width属性,但是当width属性不是在行内样式定义时,获取width属性值需要调用currentStyle方法(IE)或getComputedStyle()方法(火狐和Chrome)。本文假设为li元素设置了边框属性,相关代码如下
function getStyle(ele,attr){
if(ele.currentStyle){
return ele.currentStyle[attr];
}else{
return getComputedStyle(ele,false)[attr];
}
}
var container=document.getElementById("container");
var iLi=container.getElementsByTagName("li");
for(var i=0,length=iLi.length;i<length;i++){
iLi[i].timer=null;
iLi[i].onmouseover=function(){
bufferMove(this,500);
}
iLi[i].onmouseout=function(){
bufferMove(this,200);
}
}
function bufferMove(ele,iTarget){
clearInterval(ele.timer);
ele.timer=setInterval(function(){
var speed=(iTarget-parseInt(getStyle(ele,"width")))/10;
if(speed>0){
speed=Math.ceil(speed);
}else{
speed=Math.floor(speed);
}
if(parseInt(getStyle(ele,"width"))!=iTarget){
ele.style.width=parseInt(getStyle(ele,"width"))+speed+"px";}
},100);
}
编写方法,使该方法能够对不同的元素的不同属性改变,以产生运动效果。该方法传入三个值,分别为要操作的元素、要操作的元素属性和属性的目标值,由于透明度的属性值与其他属性值不同,需要单独考虑
<p><span style="font-weight: normal;"><span style="font-size:10px;">function bufferMove(ele,attr,iTarget){5. 多物体的链式运动
clearInterval(ele.timer);
ele.timer=setInterval(function(){
console.log(ele);
//获取当前的属性值
var icur=0;
if(attr=="opacity"){
icur=Math.round(parseFloat(getStyle(ele,attr))*100);
}else{
icur=parseInt(getStyle(ele,attr));
}
var speed=(iTarget-icur)/2;
if(speed>0){
speed=Math.ceil(speed);
}else{
speed=Math.floor(speed);
}
if(icur==iTarget){
clearInterval(ele.timer);
}else{
if(attr=="opacity"){
ele.style[attr]=(icur+speed)/100;
ele.style.filter="filter:alpha(opacity"+(icur+speed)+")";
console.log(getStyle(ele,"opacity"));
console.log(speed);
}else{
ele.style[attr]=icur+speed+"px";}
}},50);
}</span></span></p>
链式运动就是元素一次运动完成后,随后触发第二次运动。
<span style="font-size:10px;font-weight: normal;">for(var i=0,length=iLi.length;i<length;i++){6 多物体同时运动
iLi[i].timer=null;
iLi[i].icur=0;
iLi[i].onmouseover=function(){
bufferMove(this,"opacity",100,function(){
bufferMove(this,"height",100);
})
}
iLi[i].onmouseout=function(){
bufferMove(this,"height",80,function(){
bufferMove(this,"opacity",30)
});
}
}
function bufferMove(ele,attr,iTarget,fn){
clearInterval(ele.timer);
ele.timer=setInterval(function(){
//获取当前的属性值
if(attr=="opacity"){
ele.icur=Math.round(parseFloat(getStyle(ele,attr))*100);
}else{
ele.icur=parseInt(getStyle(ele,attr));
}
var speed=(iTarget-ele.icur)/2;
if(speed>0){
speed=Math.ceil(speed);
}else{
speed=Math.floor(speed);
}
if(ele.icur==iTarget){
clearInterval(ele.timer);
//传入返回的ele元素,实现函数的回调
if(fn){fn.call(ele);}
}else{
if(attr=="opacity"){
ele.style[attr]=(ele.icur+speed)/100;
ele.style.filter="filter:alpha(opacity"+(ele.icur+speed)+")";
}else{
ele.style[attr]=ele.icur+speed+"px";}
}},50);
return ele;
}</span>
多物体同时运动,需引入json
<span style="white-space: pre;"> </span><span style="font-weight: normal;"><span style="font-size:10px;">var container=document.getElementById("container");
var iLi=container.getElementsByTagName("li");
for(var i=0,length=iLi.length;i<length;i++){
iLi[i].timer=null;
iLi[i].onmouseover=function(){
bufferMove(this,{opacity:100,height:81});
}
iLi[i].onmouseout=function(){
bufferMove(this,{height:80,opacity:30});
}
}
function bufferMove(ele,json,fn){
var flag=true;
clearInterval(ele.timer);
ele.timer=setInterval(function(){
//获取当前的属性值
for(var attr in json){
if(attr=="opacity"){
ele.icur=Math.round(parseFloat(getStyle(ele,attr))*100);
}else{
ele.icur=parseInt(getStyle(ele,attr));
}
var speed=(json[attr]-ele.icur)/2;
if(speed>0){
speed=Math.ceil(speed);
}else{
speed=Math.floor(speed);
}
if(ele.icur!=json[attr]){
flag=false;
}
if(attr=="opacity"){
ele.style[attr]=(ele.icur+speed)/100;
ele.style.filter="filter:alpha(opacity"+(ele.icur+speed)+")";
}else{
ele.style[attr]=ele.icur+speed+"px";
}
if (flag) {
clearInterval(ele.timer);
//回调函数
if(fn){fn.call(ele);}
} }},50);
return ele;
}</span></span>