【原生js】—动画函数的封装

817 阅读3分钟

动画函数的封装

匀速动画

核心原理:通过定时器setInterval()不断移动盒子位置。

实现步骤:

1.获取盒子当前位置:offsetLeft

2.让盒子在当前位置加上1个移动距离: element.style.left

3.利用定时器不断重复这个操作:setInterval(fn, delay)

4.加上一个定时器的条件

5.注意此元素需要添加定位

.box{
   position: absolute;   // 必须添加定位
   width: 100px;
   height: 100px;
   background-color:orange
 }
   <div class="box"></div>

对动画函数animate的封装,需要传入四个参数:

obj: 需要做动画的元素

target::移动的目标距离

delay: 多久调用一次定时器,值越小,移动的速度越快

callback:动画执行完毕之后,执行的回调函数

    function animate(obj,target,delay,callback) {
    // obj.timer 给不同的元素指定不同的定时器
    obj.timer = setInterval(() => {
    if(obj.offsetLeft > target) {
      // 停止动画,本质就是停止定时器
       clearInterval(obj.timer);
      // 回调函数写在定时器停止之后
        callback && callback();
    }     
      // offsetLeft是只读属性,只能用来获取值,不能赋值,赋值要用element.style.left
       obj.style.left = obj.offsetLeft + 10 + 'px'    
    }, delay);       
  }
  var box = document.querySelector('.box');
    // 调用函数
  animate(box, 400, 30, function(){    // 运动到400时,弹出对话框
        alert('已经移动到400')
  })
 

以上是基本动画函数封装,但是假如现在有一个新需求,就是点击按钮之后,再让盒子做动画呢?

  .box{
    position: absolute;
    width: 100px;
    height: 100px;
    background-color:orange
   }
  
  .btn{
    position: absolute;
    top:120px;
  }
    <div class="box"></div>
    <button class="btn">按钮点击后运动</button>
 function animate(obj,target,delay,callback) {
   obj.timer = setInterval(() => {
   if(obj.offsetLeft > target) {
      clearInterval(obj.timer);
   }      
     obj.style.left = obj.offsetLeft + 10 + 'px'    
   }, delay);       
 }
   var box = document.querySelector('.box');
   var btn = document.querySelector('.btn')
   btn.addEventListener('click', function(){
    animate(box, 400, 30)
 })

但是这样写的话会有一个bug,就是连续点击按钮的时候,盒子的移动速度会慢慢变快,因为在内存中会不断创建新的定时器,定时器越多,物体移动就越快。因此,需要在调用定时器之前先清除掉内存中已有的定时器,使得只有一个定时器执行。

  function animate(obj,target,delay,callback) {
   clearInterval(obj.timer)        // 先清除掉先前的定时器,只保留当前的一个定时器执行
   obj.timer = setInterval(() => {
   if(obj.offsetLeft > target) {
      clearInterval(obj.timer);
   }      
     obj.style.left = obj.offsetLeft + 10 + 'px'    
   }, delay);       
 }
   var box = document.querySelector('.box');
   var btn = document.querySelector('.btn')
   btn.addEventListener('click', function(){
    animate(box, 400, 30)
 })

缓动动画

原理:让盒子的每次移动的距离慢慢变小,速度就会慢慢落下来。

计算公式: (目标值 - 现在的位置 ) / 10

Snipaste_2021-11-14_10-08-01.png

注意: 这里的步长值step会出现小数的情况,要把它取整,否则会使移动的位置不准确。并且还要区分是正数还是负数,如果向左移动就是负数,向下取整(Math.floor),向右移动就是正数,向上取整(Math.ceil)。

   .box{
     position: absolute;
     width: 100px;
     height: 100px;
     background-color:orange
  }
   .btn1{
     position: absolute;
     top:120px;
  }
   .btn2{
     position: absolute;
     top:120px;
     left: 120px;
  }
   <div class="box"></div>
   <button class="btn1">点击后运动800</button>
   <button class="btn2">点击后运动500</button>
   function animate(obj,target,delay,callback) {
   clearInterval(obj.timer)
   obj.timer = setInterval(() => {
   var step = (target - obj.offsetLeft) / 10     // 计算步长,这步要写在定时器里面
   step = step > 0 ? Math.ceil(step) : Math.floor(step)  // 进行判断
   if(obj.offsetLeft == target) {
      clearInterval(obj.timer);
   }   
     obj.style.left = obj.offsetLeft + step + 'px'    
   }, delay);       
 }
   var box = document.querySelector('.box');
   var btn1 = document.querySelector('.btn1')
   var btn2 = document.querySelector('.btn2')
   btn1.addEventListener('click', function(){
    animate(box, 800, 30)
 })
 
   btn2.addEventListener('click', function(){
    animate(box, 500, 30)
 })

具体案例

我们已经将动画函数封装成函数,在需要用的地方进行调用animate。

需求:鼠标经过sliderbar,导航懒从右往左移滑动出来,箭头改变, 鼠标离开sliderbar,导航栏从左往右滑动回去,箭头改变。

    .sliderbar {
       position: fixed;
       left: 0;
       top: 100px;
       width: 40px;
       height: 40px;
       text-align: center;
       line-height: 40px;
       cursor: pointer;
       color: #fff;
   }
   .con {
       position: absolute;
       right: 0;
       top: 0;
       width: 200px;
       height: 40px;
       background-color: purple;
       z-index: -1;
   }
   <div class="sliderbar">
    <span></span>
    <div class="con">问题反馈</div>
   </div>
    var sliderbar = document.querySelector('.sliderbar')
    var con = document.querySelector('.con')
    sliderbar.addEventListener('mouseenter', function(){
      animate(con, 0, 15, function(){
       // 当动画执行完毕,就把 → 改为 ←
       sliderbar.children[0].innerHTML = '←'
    })
 })
    sliderbar.addEventListener('mouseleave', function(){
      animate(con, -160, 15, function(){
       sliderbar.children[0].innerHTML = '→'
    })
 })