用js实现一个无限循环的动画

更新日期: 2019-09-09 阅读: 2.5k 标签: 动画

为什么要说它,源于看到的一道面试题:问题是用js实现一个无限循环的动画。

首先想到的是定时器

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;

    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }
    setInterval(function(){
         render()
    },1000/60)

</script>
</body>
</html>

可以说是完美实现!

至于时间间隔为什么是1000/60,这是因为大多数屏幕渲染的时间间隔是每秒60帧。

既然setInterval可以搞定为啥还要用requestAnimationFrame呢?最直观的感觉就是,添加api的人是个大神级牛人,我只能怀疑自己。

所以搜索相关问题发现以下两点


requestAnimationFrame 比起 setTimeout、setInterval的优势主要有两点:

1、requestAnimationFrame 会把每一帧中的所有dom操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。
2、在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。

直接上代码

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;

    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }

    //requestAnimationFrame效果
    (function animloop() {
        render();
        window.requestAnimationFrame(animloop);
    })();

</script>
</body>
</html>

我没有添加各个浏览器的兼容写法,这里只说用法。

效果是实现了,不过我想到两个问题。

1、怎么停止requestAnimationFrame?是否有类似clearInterval这样的类似方法?

第一个问题:答案是确定的 必须有:cancelAnimationFrame()接收一个参数 requestAnimationFrame默认返回一个id,cancelAnimationFrame只需要传入这个id就可以停止了。

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;
    var rafId = null


    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }

    //requestAnimationFrame效果
    (function animloop(time) {
        console.log(time,Date.now())
        render();
        rafId = requestAnimationFrame(animloop);
        //如果left等于50 停止动画
        if(left == 50){
            cancelAnimationFrame(rafId)
        }
    })();

    //setInterval效果
    // setInterval(function(){
    //     render()
    // },1000/60)

</script>
</body>
</html>


2、如果我想动画频率降低怎么做,为什么不考虑加快呵呵 当前刷新频率已经是屏幕的刷新频率了再快也没有意义了

这个略微麻烦点

默认情况下,requestAnimationFrame执行频率是1000/60,大概是16ms多执一次。

如果我们想每50ms执行一次怎么办呢?

requestAnimationFrame执行条件类似递归调用 (说的是类似)别咬我,既然这样的话我们能否自定一个时间间隔再执行呢?当然定时器这么low的东西我们就不考虑了,都已经抛弃它用rAF了(都快结束了我才想起写简写太他妈长了),
这个思路来源于我几年前搞IM的一个项目,服务端推送消息为了减小包的大小不给时间戳,这个我们做前端的都知道,我们虽然很牛逼 不过用户更牛逼,万一改了时间就不好玩了。

解决方案是 当和服务端通信时 记录下一个时间差,(时间差等于服务端时间-本地时间)不管正负我们只要这个时间差。这样每当我们接受到消息 或者发送消息的时候我们就拿本地时间和是价差相加。这样就可以保证和服务端时间是一致的了,思路是不是很牛逼哈哈。

撤了半天我们通过以上思路来解决下rAF改变间隔的问题

上代码

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;
    //当前执行时间
    var nowTime = 0;
    //记录每次动画执行结束的时间
    var lastTime = Date.now();
    //我们自己定义的动画时间差值
    var diffTime = 40;

    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }

    //requestAnimationFrame效果
    (function animloop() {
        //记录当前时间
        nowTime = Date.now()
        // 当前时间-上次执行时间如果大于diffTime,那么执行动画,并更新上次执行时间
        if(nowTime-lastTime > diffTime){
            lastTime = nowTime
            render();
        }
        requestAnimationFrame(animloop);

    })()
</script>
</body>
</html>

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/5819

相关推荐

css transition 实现滑入滑出

transition是css最简单的动画。 通常当一个div属性变化时,我们会立即看的变化,从旧样式到新样式是一瞬间的,嗖嗖嗖!!!但是,如果我希望是慢慢的从一种状态,转变成另外一种状态,怎么办? transition可以做到。

css3贝塞尔曲线(cubic-bezier)

css3 animation模块,其中animation-timing-function 和 transition-timing-function两个属性来控制动画速度分别提供了ease,liner,ease-in,ease-out

CSS动画@keyframes的用法

CSS动画允许大多数HTML元素的动画,而无需使用JavaScript或Flash!IE10+支持该属性的。其他低浏览器版本数字后跟-ms-, -webkit-,-moz-或-o-指定使用前缀的第一个版本。

css @keyframes属性 语法

@keyframes是CSS的一种规则,可以用来定义CSS动画的一个周期的行为,创建简单的动画。作用:通过 @keyframes 规则,您能够创建动画。

css3实现椭圆轨迹旋转

X轴Y轴在一个矩形内移动;设置动画延时设置Y轴延时为动画时长的一半, 运动轨迹变成菱形;设置三次贝塞尔曲线,为了看起来有立体感添加scale属性,scale动画应该是X轴和Y轴的时间总和

css环形滚动_内容加载的环形滚动动画效果

创建一个没有背景的圆,然后声明透明度为0.1的黑色边框(看起来是灰色),修改左侧边框颜色。此时会有一个静态的看起来只有左边框有颜色的空心圆。然后声明一个该元素逆时针旋转360度的动画,并让该动画无限播放(infinite)即可

Vue.js动画笔记_vue实现动画效果

Vue.js中的元素动画或页面跳转动画有多种实现方式比如:1、自己手动写CSS3动画来实现2、使用第三方CSS动画库如:Animate.css3、在构子函数中操作DOM4、使用第三方Js动画库如:Velocity.js。

动画函数的绘制及自定义动画函数

制作动画效果离不开动画运动函数,而我们用得最多的无疑就是Tween.js。根据不同的数学公式原理,Tween.js划分出了不同的动画类型,每种动画类型里面都包含以下的缓动类型:ease in 先慢后快、ease out 先块后慢、ease in out 先慢后快再慢

只用 CSS 就能做到的像素画/像素动画

这篇文章将会介绍只用 CSS 就能制作像素画·像素动画的方法。虽说纯 CSS 就能做到,但是为了更高的可维护性,也会顺便介绍使用 Sass 的制作方法。

css3 过渡和动画

在没有过渡属性的时候,当一个元素的属性值发生变化时,浏览器就会将个这个元素瞬间渲染成新属性值的样式。例如一个定位元素top:0,动态修改成top:100px,这个元素就瞬间跑到100px的位置,有时候我们为了达到某种视觉效果

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!