用requestAnimationFrame替代setInterval制作匀速动画

代码之前的介绍来自于这里requestAnimation介绍
了解过事件循环机制的朋友应该知道,siteTimeoutsetInterval并不是精准的时间间隔,他们要等待其他优先的执行队列执行完成以后才能继续执行。

于是就引入了一个新的动画执行方式-- window.requestAnimationFrame()。它告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

它采用的是系统时间间隔,以保证最佳的绘制效率,不会因为时间过短造成过度绘制,也不会因为时间间隔太长,产生动画卡顿的现象。让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果

特点
requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销

应用
requestAnimationFrame的用法与settimeout很相似,只是不需要设置时间间隔而已。requestAnimationFrame使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数的执行

let retID = requestAnimationFrame(callback);

取消的话可直接使用canceAnimationFrame来进行取消即可

cancelAnimationFrame(retID)

先来看个setInterval动画的例子

效果如图:
在这里插入图片描述
在这里插入图片描述
代码如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title></title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      #box {
        width: 100px;
        height: 100px;
        background-color: red;
        position: absolute;
        overflow: hidden;
      }
      .item-container {
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        align-items: center;
        height: 500px;
        width: 100px;
      }
      .item {
        width: 50px;
        height: 50px;
        background-color: blue;
        border-radius: 50%;
        margin-top: 10px;
        z-index: 100;
      }
      .open {
        width: 100px;
        height: 100px;
        line-height: 100px;
        text-align: center;
      }
    </style>
  </head>
  <body>
    <button id="btn1">改变高度</button>
    <div id="box">
      <div class="open">展开</div>
      <div class="item-container">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
        <div class="item">4</div>
        <div class="item">5</div>
      </div>
    </div>
    <script>
      window.addEventListener("load", function (ev) {
        var box = document.getElementById("box");
        var flag = true;
        // 执行动画,改变盒子高度
        document.getElementById("btn1").addEventListener("click", function (ev) {
          if (flag) {
            buffer(box, "height", 500);
            flag = false;
          } else {
            buffer(box, "height", 100);
            flag = true;
          }
        });
      });
      // 获取当前元素样式
      function getStyleAttr(obj, attr) {
        if (obj.currentStyle) {
          // IE 和 opera
          return obj.currentStyle[attr];
        } else {
          return window.getComputedStyle(obj, null)[attr];
        }
      }
      // 迅速动画函数
      function buffer(eleObj, attr, target) {
        //1.1先清后设
        clearInterval(eleObj.timer);

        var speed = 0,
          begin = 0;
        //1.2设置定时器
        eleObj.timer = setInterval(function () {
          //获取动画属性的初始值
          begin = parseInt(getStyleAttr(eleObj, attr));

          speed = (target - begin) * 0.2;
          speed = target > begin ? Math.ceil(speed) : Math.floor(speed);

          eleObj.style[attr] = begin + speed + "px";

          if (begin === target) {
            clearInterval(eleObj.timer);
          }
        }, 20);
      }
    </script>
  </body>
</html>

requestAnimationFrame代替setInterval重写buffer函数

 // 动画函数
        buffer(eleObj, attr, target) {
            // 先清后设
            cancelAnimationFrame(eleObj.timer)
            let speed = 0
            let begin = 0
            let _this = this
            eleObj.timer = requestAnimationFrame(function fn() {
                begin = parseInt(_this.getStyleAttr(eleObj, attr))
                // 动画速度
                speed = (target - begin) * 0.9
                speed = target > begin ? Math.ceil(speed) : Math.floor(speed)
                eleObj.style[attr] = begin + speed + "px"
                eleObj.timer = requestAnimationFrame(fn)
                if (begin === target) {
                    cancelAnimationFrame(eleObj.timer);
                }
            })
        },
        getStyleAttr(obj, attr) {
            if (obj.currentStyle) {
              // IE 和 opera
              return obj.currentStyle[attr];
            } else {
              return window.getComputedStyle(obj, null)[attr];
            }
        }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jieyucx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值