JavaScript动画
1、动画方法:
可以用CSS3的animattion+keyframes;
可以用CSS3的transition;
可以用canvas上作图来实现动画;
可以用jQuery动画相关API方便实现;
可以用widow.setTimeout()或者window.setInterval(),通过不断更新元素状态位置等来实现动画,前提动画更新频率达到每秒60此才能流畅的动画效果。
可以用window.requestAnimationFrame()方法来实现动画
2、widnow.requsetAnimationFrame()方法
原理与setTimeout/setInterval差不多,通过递归调用同一方法来不断更新画面以达到动起来的效果,
但它优于setTimeout/setInrerval的地方在于它是由浏览器专门为动画提供的API,在运行时浏览器会自动调用优化方法的调用,
并且如果也没不是激活状态下,动画会自动暂停,节省CPU。
(1)语法
可以直接调用,也可以通过window来调用,接受一个函数作为回调,返回一个ID值,通过这个ID值传给widow.cancelAnimationFrame()可以取消该动画
requestAnimationFrame(callback) //callback回调函数
例子:
<div id="test" style="width:1px;height:17px;background:#0f0" >%<div>
<input type="buttom" value="run" id="run">
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;var start = null;var ele = document.getElementById("test");var progress = 0;function step() {
progress += 1;
ele.style.width = progress + "%";
ele.innerHTML=progress + "%";
if (progress < 100) {
requestAnimationFrame(step);//自己循环
}
}
requestAnimationFrame(step);
//首先执行一次document.getElementById("run").addEventListener("click", function() {
ele.style.width = "1px";
progress = 0;
requestAnimationFrame(step);
例子2:
<!DOCTYPE html><html>
<head>
<title>Script-based animation using requestAnimationFrame</title>
<style type="text/css">
#animated {
position: absolute; top:100px;
padding: 50px; background: crimson; color: white;
}
</style>
</head>
<body>
<div>Click the box to stop and start it</div>
<div id="animated">Hello there.</div>
<script type="text/javascript">
var elm=document.getElementById("animated");
var handle=0;
var Ipos=0;
function renderLoop(){
elm.style.left=((Ipos+=3)%600)+"px";//Ipos+3控制移动速度,600控制最长移动距离。
handle=widow.requestAnimationFrame(renderLoop);//告诉浏览器要执行的动画,请求请求浏览器在下一帧重绘窗口。一遍有一遍循环
};
renderLoop();//调用函数运行
document.getElementById("animated").addEventListener("click",function(){
if(handle){//当handle非0时,执行函数
window.canceAnimationFrame(renderLoop);//取消动画运行
handle=null
}else{
renderLoop();
}
},false );
</script>
</body>
</html>
本示例使用getElementById将div元素保存在一个全局变量中,调用renderLoop()函数开始动画。在重新定位div元素后,在此调用requestAnimationFrame以设置下一次移动。此操作将继续执行,直至关闭浏览器或者单击div元素位置。
addEventListener方法处理div元素上的单击事件。当你单击元素时,将使用句柄
(2)对requestAnimationFrame更牢靠的封装
(function(){
var lastTime=0;
var vendors=['webkit','moz'];
fo(var x=0;x<vedor.length && !window.requestAnimationFrame:++x){
window.requestAnimationFrame=window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame=window.[vendors[x]+'CancelAnimation'] || window.[vendors[x]+'CancelRequestAnimationFrame'];
};
if(!window.requestAnimationFrame)
window.requestAnimationFrame=function(callback,element){
var curTime=new Date().getTime();
var timeToCall=Math.(0,16-(curTime-lastTime));
var id=window.setTime(function(){
callback(currTime+timeToCall);},
);
lastTime=currTime+timeToCall;
return id;
};
if(!window.cancelAnimationFrame)
window.cancelAnimationFrame=function(id){
clearTime(id);
};
})();
元素位置运动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
#id1{
width: 200px;
height: 200px;
background-color: red;
position: absolute;
left: -180px;
}
</style>
</head>
<body>
<div id="id1" class="id1">
</div>
</body>
<script>
window.onload=function(){
var oDiv=document.getElementById("id1");
oDiv.onmouseover=function(){
startMove(0);
}
oDiv.onmouseout=function(){
startMove(-180);
}
};
var time=null;//定义定时器
/*function startMoveIn(target){
clearInterval(time);//一进入清除定时器,防止效果叠加
var oDiv=document.getElementById("id1");
time=setInterval(function(){
if(oDiv.offsetLeft==target){
clearInterval(time);
}else{
oDiv.style.left=oDiv.offsetLeft+1+"px";
}
},30)
}*/
function startMove(target){
clearInterval(time);//一进入清除定时器,防止效果叠加
var oDiv=document.getElementById("id1");
var speed=0;
if(oDiv.offsetLeft>target){
speed=-1;
}
else{
speed=1;
}
time=setInterval(function(){
if(oDiv.offsetLeft==target){
clearInterval(time);
}else{
oDiv.style.left=oDiv.offsetLeft+speed+"px";
}
},1)
}
</script>
</html>
元素透明度
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#id1{
width: 200px;
height: 200px;
background-color: red;
position: absolute;
left:180px;
opacity: 0.3;
}
</style>
</head>
<body>
<div id="id1" class="id1">
</div>
</body>
<script type="text/javascript">
window.onload=function(){
var oDiv=document.getElementById("id1");
oDiv.onmouseover=function(){
changeOpacity(100);
};
oDiv.onmouseout=function(){
changeOpacity(30);
}
};
var time=null;
var alpha=30;
function changeOpacity(target){
clearInterval(time);//进入先清除以前保留的定时器
var oDiv=document.getElementById("id1");
var speed=0;
var time=setInterval(function(){
if(target>alpha){
speed=10;
}else{
speed=-10;
}
if(alpha==target){
clearInterval(time);
}else{
alpha+=speed;
}
oDiv.style.filter='alpha('+alpha+')';//IE下
oDiv.style.opacity=alpha/100;
},30)
}
</script>
</html>
缓冲动作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
#id1{
width: 200px;
height: 200px;
background-color: red;
position: absolute;
}
</style>
</head>
<body>
<div id="id1" class="id1" style="left: -180px;">
</div>
</body>
<script>
/*
* math.floor() 向下取整
* math.ceil() 向上取整
* */
window.onload=function(){
oDiv=document.getElementById("id1");
oDiv.onmouseover=function(){
startMove(0);
}
oDiv.onmouseout=function(){
startMove(-180);
}
};
var time=null;//定义定时器
/*function startMoveIn(target){
clearInterval(time);//一进入清除定时器,防止效果叠加
var oDiv=document.getElementById("id1");
time=setInterval(function(){
if(oDiv.offsetLeft==target){
clearInterval(time);
}else{
oDiv.style.left=oDiv.offsetLeft+1+"px";
}
},30)
}*/
function startMove(target){
clearInterval(time);//一进入清除定时器,防止效果叠加
var oDiv=document.getElementById("id1");
time=setInterval(function(){
var speed=(target-oDiv.offsetLeft)*0.05;
/*当大于0向上取整,当小于0向下取整*/
speed=speed>0?Math.ceil(speed):Math.floor(speed);
if(oDiv.offsetLeft==target){
clearInterval(time);
}else{
oDiv.style.left=oDiv.offsetLeft+speed+"px";
}
},30)
}
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
div{
width: 200px;
height: 200px;
background-color: red;
position: relative;
margin: 10px;
opacity: 0.3;
}
</style>
</head>
<body>
<div id="id1" class="id1"></div>
<div id="id2" class="id1"></div>
<div id="id3" class="id1"></div>
<div id="id4" class="id1"></div>
</body>
<script type="text/javascript">
window.onload=function(){
var oDiv=document.getElementsByClassName("id1");
for(var i=0;i<oDiv.length;i++){
oDiv[i].alpha=30;
oDiv[i].onmouseover=function(){
changeOpacity(this,100);
};
oDiv[i].onmouseout=function(){
changeOpacity(this,30);
}
}
};
//var time=null; 为每个定时器设置id
//var alpha=30;由于是多个元素,多个元素不能共享同一个值,所以把alpha加入到oDiv的属性中,为每个元素保存一个alpha
function changeOpacity(obj,target){
clearInterval(obj.time);//进入先清除以前保留的定时器
var speed=0;
obj.time=setInterval(function(){
if(target>obj.alpha){
speed=+10;
}else{
speed=-10;
}
if(obj.alpha==target){
clearInterval(obj.time);
}else{
obj.alpha+=speed;
obj.style.filter='alpha(opacity:'+obj.alpha+')';//IE下
obj.style.opacity=obj.alpha/100;
}
},30)
}
</script>
</html>
传递参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
li{
list-style-type: none;
width: 200px;
height: 200px;
background-color: #b2dba1;
margin: 10px 0;
border: 4px solid black;
}
</style>
</head>
<body>
<ul>
<li id="li1">a</li>
<li id="li2">b</li>
<li>c</li>
</ul>
</body>
<script>
window.onload=function(){
/* var list=document.getElementsByTagName("li");
for(var i=0;i<=list.length;i++){
list[i].onmouseover=function(){
startMove(this,400)
};
list[i].onmouseout=function(){
startMove(this,200)
}
}*/
var li1=document.getElementById("li1");
var li2=document.getElementById("li2");
li1.onmouseover=function(){
startMove(this,"height",400);
};
li1.onmouseout=function(){
startMove(this,"height",200);
};
li2.onmouseover=function(){
startMove(this,"width",400);
};
li2.onmouseout=function(){
startMove(this,"width",200);
}
};
/*
*
*
* */
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];//IE
}else{
return getComputedStyle(obj,false)[attr];//chrome
}
}
function startMove(obj,attr,target){
clearInterval(obj.time);//会对多个定时器造成清空,为了解决这个情况,为每个定时器加上标记
obj.time=setInterval(function(){
var icur=parseInt(getStyle(obj,attr));
var speed=(target-icur)/10;
speed=speed>0?Math.ceil(speed):Math.floor(speed);
if(icur==target){
clearInterval(obj.time);
}else{
obj.style[attr]=icur+speed+"px";
}
},30)
}
</script>
</html>
如果传入的参数是透明度如何处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
li{
list-style-type: none;
width: 200px;
height: 200px;
background-color: #b2dba1;
margin: 10px 0;
border: 4px solid black;
opacity: 0.5;
}
</style>
</head>
<body>
<ul>
<li id="li1">a</li>
<li id="li2">b</li>
<li>c</li>
</ul>
</body>
<script>
window.onload=function(){
/* var list=document.getElementsByTagName("li");
for(var i=0;i<=list.length;i++){
list[i].onmouseover=function(){
startMove(this,400)
};
list[i].onmouseout=function(){
startMove(this,200)
}
}*/
var li1=document.getElementById("li1");
var li2=document.getElementById("li2");
li1.onmouseover=function(){
startMove(this,"height",400);
};
li1.onmouseout=function(){
startMove(this,"height",200);
};
/*li2.onmouseover=function(){
startMove(this,"width",400);
};
li2.onmouseout=function(){
startMove(this,"width",200);
};*/
li2.onmouseover=function(){
startMove(this,"opacity",100);
};
li2.onmouseout=function(){
startMove(this,"opacity",50);
}
};
/*
*
*
* */
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];//IE
}else{
return getComputedStyle(obj,false)[attr];//chrome
}
}
/*
* Math.round()四舍五入
* */
function startMove(obj,attr,target){
clearInterval(obj.time);//会对多个定时器造成清空,为了解决这个情况,为每个定时器加上标记
obj.time=setInterval(function(){
var icur=0;
if(attr=="opacity"){
icur=Math.round(parseFloat(getStyle(obj,attr))*100);
//icur=parseFloat(getStyle(obj,attr))*100;
}else{
icur=parseInt(getStyle(obj,attr));
}
var speed=(target-icur)/20;
speed=speed>0?Math.ceil(speed):Math.floor(speed);
if(icur==target){
clearInterval(obj.time);
}else{
if(attr=="opacity"){
obj.style.filter='alpha(opacity:'+(icur+speed)+')';//IE下
obj.style.opacity=(icur+speed)/100;
}else{
obj.style[attr]=icur+speed+"px";
}
}
},30)
}
</script>
</html>
链式运动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
li{
list-style-type: none;
width: 200px;
height: 200px;
background-color: #b2dba1;
margin: 10px 0;
opacity: 0.5;
}
</style>
</head>
<body>
<ul>
<li id="li1">a</li>
<li id="li2">b</li>
<li>c</li>
</ul>
</body>
<script>
window.onload=function(){
var li1=document.getElementById("li1");
li1.onmouseover=function(){
startMove(li1,"width",450,function(){
startMove(li1,"height",500,function(){
startMove(li1,"opacity",80)
});
})
}
};
/*
*
*
* */
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];//IE
}else{
return getComputedStyle(obj,false)[attr];//chrome
}
}
/*
* Math.round()四舍五入
* */
function startMove(obj,attr,target,fn){
clearInterval(obj.time);//会对多个定时器造成清空,为了解决这个情况,为每个定时器加上标记
obj.time=setInterval(function(){
var icur=0;
if(attr=="opacity"){
icur=Math.round(parseFloat(getStyle(obj,attr))*100);
//icur=parseFloat(getStyle(obj,attr))*100;
}else{
//icur=parseInt(getStyle(obj,attr));
icur=parseInt(getStyle(obj,attr));
}
var speed=(target-icur)*0.5;
speed=speed>=0?Math.ceil(speed):Math.floor(speed);
if(icur==target){
clearInterval(obj.time);
if(fn){ //当运动停止的后,调用回调函数
fn();
}
}else{
if(attr=="opacity"){
obj.style.filter='alpha(opacity:'+(icur+speed)+')';//IE下
obj.style.opacity=(icur+speed)/100;
}else{
obj.style[attr]=icur+speed+"px";
}
}
},30)
}
</script>
</html>
多物体运动 完美的框架
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
li{
list-style-type: none;
width: 200px;
height: 200px;
background-color: #b2dba1;
margin: 10px 0;
opacity: 0.5;
}
</style>
</head>
<body>
<ul>
<li id="li1">a</li>
<li id="li2">b</li>
<li>c</li>
</ul>
</body>
<script>
window.onload=function(){
var li1=document.getElementById("li1");
li1.onmouseover=function(){
startMove(li1,{"width":500,"height":500,"opacity":50})
}
li1.onmouseout=function(){
startMove(li1,{"width":100,"height":100,"opacity":30})
}
};
/*
*
*
* */
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];//IE
}else{
return getComputedStyle(obj,false)[attr];//chrome
}
}
/*
* Math.round()四舍五入
* */
//startMove(obj,{attr1:target1,attr2:target2},fn)
function startMove(obj,json,fn){
var flag=true;//设置一个标杆
clearInterval(obj.time);//会对多个定时器造成清空,为了解决这个情况,为每个定时器加上标记
obj.time=setInterval(function() {
for(var attr in json){
var icur = 0;
if (attr == "opacity") {
icur = Math.round(parseFloat(getStyle(obj, attr)) * 100);
//icur=parseFloat(getStyle(obj,attr))*100;
} else {
//icur=parseInt(getStyle(obj,attr));
icur = parseInt(getStyle(obj, attr));
}
var speed = (json[attr] - icur) * 0.05;
speed = speed >= 0 ? Math.ceil(speed) : Math.floor(speed);
if (icur != json[attr]) { //当存在任何一个属性值不等于目标值的时候
flag=false;//把标杆置为false,紧接着进行属性操作
if (attr == "opacity") {
obj.style.filter = 'alpha(opacity:' + (icur + speed) + ')';//IE下
obj.style.opacity = (icur + speed) / 100;
} else {
obj.style[attr] = icur + speed + "px";
}
}
}
if(flag){//如果flag为true,则说明全部都完成动画
clearInterval(obj.time);
if(fn){
fn();
}
}
},30)
}
</script>
</html>