使用requestAnimationFrame做动画效果一,Javascript动画

日期:2019-12-05编辑作者:服务器

假设有这样一个动画功能需求:把一个div的宽度从100px变化到200px。写出来的代码可能是这样的:复制代码 代码如下:

Javascript动画的实现原理浅析

 这篇文章主要介绍了Javascript动画的实现原理浅析,本文用两个实例来解释Javascript动画的实现原理,需要的朋友可以参考下

 

 

假设有这样一个动画功能需求:把一个div的宽度从100px变化到200px。写出来的代码可能是这样的:

代码如下:

<div id="test1" style="width: 100px; height: 100px; background: blue; color: white;"></div>
function animate1(element, endValue, duration) {
var startTime = new Date(),
startValue = parseInt(element.style.width),
step = 1;

var timerId = setInterval(function() {
var nextValue = parseInt(element.style.width) + step;
element.style.width = nextValue + 'px';
if (nextValue >= endValue) {
clearInterval(timerId);
// 显示动画耗时
element.innerHTML = new Date - startTime;
}
}, duration / (endValue - startValue) * step);
}

 

animate1(document.getElementById('test1'), 200, 1000);

原理是每隔一定时间增加1px,一直到200px为止。然而,动画结束后显示的耗时却不止1s(一般是1.5s左右)。究其原因,是因为setInterval并不能严格保证执行间隔。

 

有没有更好的做法呢?下面先来看一道小学数学题:

代码如下:

A楼和B楼相距100米,一个人匀速从A楼走到B楼,走了5分钟到达目的地,问第3分钟时他距离A楼多远?
匀速运动中计算某个时刻路程的计算公式为:路程 * 当前时间 / 时间 。所以答案应为 100 * 3 / 5 = 60 。

 

这道题带来的启发是,某个时刻的路程是可以通过特定公式计算出来的。同理,动画过程中某个时刻的值也可以通过公式计算出来,而不是累加得出:

 

代码如下:

<div id="test2" style="width: 100px; height: 100px; background: red; color: white;"></div>
function animate2(element, endValue, duration) {
var startTime = new Date(),
startValue = parseInt(element.style.width);

 

var timerId = setInterval(function() {
var percentage = (new Date - startTime) / duration;

var stepValue = startValue + (endValue - startValue) * percentage;
element.style.width = stepValue + 'px';

if (percentage >= 1) {
clearInterval(timerId);
element.innerHTML = new Date - startTime;
}
}, 13);
}

animate2(document.getElementById('test2'), 200, 1000);

 

这样改良之后,可以看到动画执行耗时最多只会有10几ms的误差。但是问题还没完全解决,在浏览器开发工具中检查test2元素可以发现,test2的最终宽度可能不止200px。仔细检查animate2函数的代码可以发现:

1.percentage的值可能大于1,可以通过Math.min限制最大值解决。
2.即使保证了percentage的值不大于1,只要endValue或startValue为小数,(endValue

  • startValue) * percentage的值也可能产生误差,因为Javascript小数运算的精度不够。其实我们要保证的只是最终值的准确性,所以在percentage为1的时候,直接使用endValue即可。

于是,animate2函数的代码修改为:

代码如下:

function animate2(element, endValue, duration) {
var startTime = new Date(),
startValue = parseInt(element.style.width);

 

var timerId = setInterval(function() {
// 保证百分率不大于1
var percentage = Math.min(1, (new Date - startTime) / duration);

var stepValue;
if (percentage >= 1) {
// 保证最终值的准确性
stepValue = endValue;
} else {
stepValue = startValue + (endValue - startValue) * percentage;
}
element.style.width = stepValue + 'px';

if (percentage >= 1) {
clearInterval(timerId);
element.innerHTML = new Date - startTime;
}
}, 13);
}

 

还有最后一个疑问:setInterval的间隔为何设为13ms?原因是当下显示器的刷新率一般不超过75Hz(即每秒刷新75次,也就是每隔约13ms刷新一次),把间隔跟刷新率同步效果更好。

这篇文章主要介绍了Javascript动画的实现原理浅析,本文用两个实例来解释Javascript动画的实现原理,需要的朋友可...

      最近学习了requestAnimationFrame,看了张鑫旭直白易懂,但是某些地方语言过于裸露的文章,文章里的例子:让我觉得这个requestAnimationFrame很厉害,虽然我对动画的接触还不多,但是我会努力的。

function animate1(element, endValue, duration) { var startTime = new Date(), startValue = parseInt, step = 1; var timerId = setInterval { var nextValue = parseInt + step; element.style.width = nextValue + 'px'; if (nextValue >= endValue) { clearInterval; // 显示动画耗时 element.innerHTML = new Date - startTime; } }, duration / (endValue - startValue) * step);}

相关文章

相关搜索:

今天看啥

搜索技术库

返回首页

  • iPhone激活是什么
  • OPPO R7如何拍摄gif动画
  • 三星S6Edge怎么拍摄GIF图片
  • 红米2自动接听怎么设置?
  • CAD迷你看图怎么测距
  • 手机YY怎么说话

相关频道: HTML/CSS  HTML5  Javascript  jQuery  AJax教程  前端代码  正则表达式  Flex教程  WEB前端教程  

     requestAnimationFrame是什么么?

animate1(document.getElementById;原理是每隔一定时间增加1px,一直到200px为止。然而,动画结束后显示的耗时却不止1s。究其原因,是因为setInterval并不能严格保证执行间隔。

帮客评论

     requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API: 

有没有更好的做法呢?下面先来看一道小学数学题:复制代码 代码如下:A楼和B楼相距100米,一个人匀速从A楼走到B楼,走了5分钟到达目的地,问第3分钟时他距离A楼多远?匀速运动中计算某个时刻路程的计算公式为:路程 * 当前时间 / 时间 。所以答案应为 100 * 3 / 5 = 60 。

     说简单点

这道题带来的启发是,某个时刻的路程是可以通过特定公式计算出来的。同理,动画过程中某个时刻的值也可以通过公式计算出来,而不是累加得出:

    • setInterval、setTimeout是开发者主动要求浏览器去绘制,但是由于种种问题,浏览器可能会漏掉部分命令
    • requestAnimationFrame 就是浏览器什么要开始绘制了浏览器自己知道,通过requestAnimationFrame 告诉开发者,这样就不会出现重复绘制丢失的问题了
    • requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧
    • 隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。
    • requestAnimationFrame也会像setTimeout一样有一个返回值ID用于取消,可以把它作为参数传入cancelAnimationFrame函数来取消requestAnimationFrame的回调

复制代码 代码如下:

 下面是一个简单的例子:

function animate2(element, endValue, duration) { var startTime = new Date(), startValue = parseInt;

 <!doctype html><img id="book" style="background:red;opacity:1;position: relative; left: 500px;" alt="" width="100" height="123" data-mce-style="background: red; opacity: 1; position: relative; left: 500px;" /><div id="several"><br /></div><script type="text/javascript"> var book = document.getElementById('book') var several = document.getElementById('several'); animate(book, { left: 50, duration: 2000 }) function animate(elem, options){ //动画初始值 var start = 500 //动画结束值 var end = options.left //动画id var timerId; var createTime = function(){ return (+new Date) } //动画开始时间 var startTime = createTime(); var i = 0; function tick(){ i++; several.innerHTML = 'setInterval调用次数:' + i; //每次变化的时间 var remaining = Math.max(0, startTime + options.duration - createTime()) var temp = remaining / options.duration || 0; var percent = 1 - temp; var stop = function(){ //停止动画 clearInterval(timerId); timerId = null; } var setStyle = function(value){ elem.style['left'] = value + 'px' } //移动的距离 var now = (end - start) * percent + start; if(percent === 1){ setStyle(now) stop(); }else{ setStyle(now) } } //开始执行动画 var timerId = setInterval(tick, 13); } </script>

var timerId = setInterval { var percentage = / duration;

    此处不用点了,因为我无法向页面添加js代码,可是,为什么我看到别人的博客中可以呢,伤心。

var stepValue = startValue + (endValue - startValue) * percentage; element.style.width = stepValue + 'px';

      function runCode(cod1) {
        var cod = window.document.all(cod1)
        var code = cod.value;
        var newwin = window.document.open('', '', '');
        newwin.opener = null
        newwin.document.write(code);
        newwin.document.close();
    }

if { clearInterval; element.innerHTML = new Date - startTime; } }, 13);}

 

animate2(document.getElementById;

      我做了个练习:

这样改良之后,可以看到动画执行耗时最多只会有10几ms的误差。但是问题还没完全解决,在浏览器开发工具中检查test2元素可以发现,test2的最终宽度可能不止200px。仔细检查animate2函数的代码可以发现:

      每隔1s长生一个小方块,让其匀速下落,落到底部消失,如果碰到底部中间的方块,小方块消失,分数加1,这个例子还有很多不足的地方,我会继续完善:

1.percentage的值可能大于1,可以通过Math.min限制最大值解决。2.即使保证了percentage的值不大于1,只要endValue或startValue为小数,(endValue

 1 <script>
 2             window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
 3             var h=0;
               var timer=setInterval(function(){
 4             if(h>40){
 5                 clearInterval(timer);return;
 6             }else{
 7             h+=1;
 8             var isSucceed;
 9             var isOnBelow;
10             var isStillOn;
11             var dotX;    
12             var dot=new Dot();
13             dotX=dot.getName();
14             isStillOn=true;
15             animate(dot.dom, {
16                 top: window.innerHeight-dot.dom.offsetHeight,
17                 duration: 3000
18             });
19             function animate(elem, options){
20                 //动画初始值
21                 var start = 0
22                 //动画结束值
23                 var end = options.top
24                 var createTime = function(){
25                     return  (+new Date)
26                 }
27                 //动画开始时间
28                 var startTime = createTime();
29                 var timerId;
30                 //开始动画
31                 var startAnim = function() {
32                     timerId = requestAnimationFrame(tick,15);
33                 }
34                 //停止动画
35                 var stopAnim = function() {
36                     cancelAnimationFrame(timerId)
37                 }
38                 var number=0;
39                 var isRemove=true;
40                 function tick(){    
41                     number++;
42                     //每次变化的时间
43                     var remaining = Math.max(0, startTime + options.duration - createTime())
44                     var temp = remaining / options.duration || 0;
45                     var percent = 1 - temp;
46                     var setStyle = function(value){
47                         elem.style['top'] = value + 'px';
48                         var centerW=center.offsetLeft;
49                         var centerH=center.offsetTop;
50                         if(value>=(centerH-42)){
51                             isOnBelow=true;
52                         }else{
53                             isOnBelow=false;
54                         }
55                        if(dotX>=(centerW-50)&&dotX<=(centerW+200)){
56                             isSucceed=true;
57                         }else{
58                             isSucceed=false;
59                         }
60                     }
61                     if(isRemove&&isOnBelow&&isSucceed){
62                         isRemove=false;
63                         stopAnim() ;
64                         document.getElementById("view").removeChild(elem);
65                         isStillOn=false;
66                         count++;
67                         document.getElementById("count").innerHTML="总分为:"+count+"分";
68                     }
69                     //移动的距离
70                     var now = (end - start) * percent + start;
71                     if(percent === 1){
72                         setStyle(now);
73                         if(isStillOn){
74                             document.getElementById("view").removeChild(elem);
75                         }
76                         stopAnim() ;
77                     }else{
78                         setStyle(now);
79                         startAnim(tick);
80                     }
81                 }
82                 //开始执行动画
83                 startAnim(tick);
84             }
85         }},1000)
86         document.getElementById("center").addEventListener("touchmove",function(e){
87                  var touch=e.targetTouches[0].pageX;
88                  // if(touch<0){touch=100;}
89                  // if(touch>(document.body.clientWidth-center.clientWidth)){touch=document.body.clientWidth-center.clientWidth+100}    
90                  document.getElementById("center").style.left=touch+"px";
91         });
92         
93     </script>
  • startValue) * percentage的值也可能产生误差,因为Javascript小数运算的精度不够。其实我们要保证的只是最终值的准确性,所以在percentage为1的时候,直接使用endValue即可。

 

于是,animate2函数的代码修改为:复制代码 代码如下:function animate2(element, endValue, duration) { var startTime = new Date(), startValue = parseInt;

var timerId = setInterval { // 保证百分率不大于1 var percentage = Math.min(1, / duration);

var stepValue; if { // 保证最终值的准确性 stepValue = endValue; } else { stepValue = startValue + (endValue - startValue) * percentage; } element.style.width = stepValue + 'px';

if { clearInterval; element.innerHTML = new Date - startTime; } }, 13);}

还有最后一个疑问:setInterval的间隔为何设为13ms?原因是当下显示器的刷新率一般不超过75Hz(即每秒刷新75次,也就是每隔约13ms刷新一次),把间隔跟刷新率同步效果更好。

本文由澳门金莎娱乐网站发布于服务器,转载请注明出处:使用requestAnimationFrame做动画效果一,Javascript动画

关键词:

澳门金莎娱乐网站:javascript处理表单示例_基础知

以上就是本文的全部内容了,希望对大家能够有所帮助。 EasyUI中实现form表单提交的示例分享 这里给大家分享的是一...

详细>>

最近一段时间的一些学习,EasyUI实现二级页面的

EasyUI,在增、删的时候,经常用到二级页面进行勾选。 EasyUI实现二级页面的内容勾选的方法  在使用EasyUI的时候,我...

详细>>

选择器演示代码_jquery_脚本之家澳门金莎娱乐网站

[Ctrl+A 全选 注:如需引进外界Js需刷新技术实行] style for display none's div 档次选拔器准则如下: 全然演示代码: class 为...

详细>>

兼容IE与firefox火狐的回车事件,jQuery事件之键盘

代码一:keypress事件时使用 复制代码代码如下:/****************************************************///功能:过滤非法字符 //说明:...

详细>>