组件分享之 JavaScript 运动框架

发布于 2021-11-26 13:19:41 字数 6311 浏览 1355 评论 0

JS 原生运动组件

Why?

大家都知道 JQuerry 有 animate 方法来给 DOM 元素进行运动,CSS3 中也有 transition、transform 来进行运动。而使用原生的 JavaScript 来控制元素运动,需要写很多运动的细节以及兼容。

然而,当你的 BOSS 不让你使用庞大的 JQ 框架,而且你开发的产品也需要在一些不兼容 CSS3 的浏览器运行的时候,你是否觉得每次都要开个定时器来琢磨运动该怎么进行,是件很费力的事情呢?

那么福利来了,笔者最近总结了两个常用的运动框架,并将其写成组件,只要按照下面的方法调用,即可方便使用。

1.在你的页面中引入 js

<script src="Mover.js"></script>

2.在你的 js 代码中创建 Mover 对象

window.onload=function(){
  var mover = new Mover();
};

3.开始使用 mover!

用法说明:笔者写的组件包含了两种运动框架供使用,一种是基于速度的;一种是基于时间的,让我们来先看看基于速度的运动框架的用法

startMoveBySpeed(obj, json, endFn);

  • 参数 obj : 传入要运动的对象
  • 参数 json : 以json的形式传入要运动的属性,包括 left、top、width、height 等以 px 为单位的属性和透明度 opacity,他们的值是运动的终点
  • 参数 endFn(可选) : 结束运动后要执行的方法
//基于速度的运动框架用法
window.onload=function(){
  //得到你要运动的元素
  var oDiv = document.getElementsByTagName('div')[0];
  
  //使用运动框架
  var mover = new Mover();
  oDiv.onclick=function(){  
    mover.startMoveBySpeed(this,{'left':200,'width':300,'opacity':50});
  //使oDiv的left运动到200px,宽度变为300px,透明度变为50%
  }
};

让我们来看看另外一种基于时间的运动框架

startMoveByTime(obj, json, options, endFn )

  • 参数 obj : 传入要运动的对象
  • 参数 json : 以 json 的形式传入要运动的属性,包括 left、top、width、height 等以 px 为单位的属性和透明度 opacity,他们的值是运动的终点
  • 参数 options : 以 json 的形式传入传入运动的总时间和运动方式,如:
    {
    'times' : 1000,//运动总时间为 1s
    'fx' : 'linear' // 运动形式为匀速
    }
    当options传入参数为空 json{} 时,就使用默认设置(运动时间500ms,运动形式为匀速)
  • 参数 endFn(可选) : 结束运动后要执行的方法
//基于事件的运动框架用法
window.onload=function(){
  //得到你要运动的元素
  var oDiv = document.getElementsByTagName('div')[0];
  //使用运动框架
  var mover = new Mover();
  oDiv.onclick=function(){
    mover.startMoveByTime(
      this, 
      {'left':500,'top':200}, 
      {'times':1000,'fx':'easeIn'}, 
      function(){
        mover.startMoveByTime(this,{'opacity':20},{});
    });
    //使oDiv的left变为500px,高度变为200px,结束上述运动后再使透明度变为20%
  }
}

区别

现在来说说两种方式的区别吧,使用第一种方式进行运动时,元素的各项需要改变的属性的运动速度相同,而由于每项属性起点到终点的距离不一样,所以各项属性到达运动终点的时间也不一样。而第二种运动直接固定了运动总时间相同,所以所有传入参数的属性一起改变、一起终止。

源码

以下是 Mover.js 组件的代码,欢迎指正,后面有时间也会将弹性运动、碰撞运动、重力运动一起写入框架

/*
  js原生运动组件
*/

//Mover构造函数
function Mover(){
  this.setting = {
    'times' : 500,
    'fx' : 'linear'
  }
}

//获取当前样式
Mover.prototype.getStyle = function(obj,attr)
{
  return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj)[attr];
}

//获取当前时间
Mover.prototype.now = function(){
    return (new Date()).getTime();
}

//速度版运动框架
Mover.prototype.startMoveBySpeed = function (obj,json,fnEnd)
{
  clearInterval(obj.timer);
  _this = this;
  obj.timer = setInterval(function(){
    obj.bStop = true;
    for(var attr in json)
    {
      var cur = 0;
      var speed = 0;
      if(attr === 'opacity')
      {
        cur = _this.getStyle(obj,attr);
        cur = Math.round( parseFloat(cur*100) );
      }
      else
      {
        cur = parseInt(_this.getStyle(obj,attr));
      }

      var speed = (json[attr]-cur)/8;

      speed = speed ? Math.ceil(speed):Math.floor(speed);

      if(cur !== json[attr])
      {
        obj.bStop = false;
      }

      if(attr === 'opacity')
      {
        obj.style.opacity = (cur+speed)/100;
        obj.style.filter = 'Alpha(opacity:'+(cur+speed)+')';
      }
      else
      {
        obj.style[attr] = (cur+speed)+'px';
      }
    }

    if(obj.bStop)
    {
      clearInterval(obj.timer);
      fnEnd && fnEnd.call(obj);
    }

  },20);
}

//时间版运动框架
Mover.prototype.startMoveByTime = function(obj,json,options,endFn){
  //对于时间版框架来说,初始值b是固定的,所以写在定时器外面
  var _this = this;
  //默认设置
  extend(_this.setting,options);

  var iCur = {};
  //获取当前值
  for(attr in json)
  {
    iCur[attr] = 0;

    if(attr === 'opacity')
    {
      iCur[attr] = Math.round( parseFloat( _this.getStyle(obj,attr) )*100 );
    }else{
      iCur[attr] = parseInt( _this.getStyle(obj,attr) );
    }

  };
  
  var iStartTime = _this.now();
  clearInterval(obj.timer);
  obj.timer = setInterval(function(){
    var iCurTime = _this.now();
    var t = _this.setting.times-
    Math.max(0,iStartTime-iCurTime+_this.setting.times);
    for(attr in json)
    {  
      /*
        Tween[fx]函数4个参数
        t:current  time(当前时间)
        b:beginning  value(初始值)
        c: change  in  value(变化量)
        d:duration(持续时间)
        return  (目标点)  
      */
      var value = _this.Tween[_this.setting.fx](
        t,            //t  0~times
        iCur[attr],        //b
        json[attr]-iCur[attr],  //c
        _this.setting.times           //d
       );
      if(attr === 'opacity')
      {
        obj.style[attr] =  parseFloat(value/100);
        obj.style.filter = 'alpha(opacity:'+value+')';
      }else{
        obj.style[attr] = value + 'px';
      }

    }

    if( t === _this.setting.times )
    {
      clearInterval(obj.timer);
      endFn && endFn.call(obj);
    }
  },13);
    
}
//覆盖默认设置
function extend(child,father){
  for(var attr in father)
  {
    child[attr] = father[attr];
  }
}
//Tween运动算法
Mover.prototype.Tween = {
  /*
    4个参数
    t:current  time(当前时间)
    b:beginning  value(初始值)
    c: change  in  value(变化量)
    d:duration(持续时间)
    return  (目标点)

  */

  linear: function (t, b, c, d){  //匀速
    return c*t/d + b;
  },
  easeIn: function(t, b, c, d){  //加速曲线
    return c*(t/=d)*t + b;
  },
  easeOut: function(t, b, c, d){  //减速曲线
    return -c *(t/=d)*(t-2) + b;
  },
  easeBoth: function(t, b, c, d){  //加速减速曲线
    if ((t/=d/2) < 1) {
      return c/2*t*t + b;
    }
    return -c/2 * ((--t)*(t-2) - 1) + b;
  },
  easeInStrong: function(t, b, c, d){  //加加速曲线
    return c*(t/=d)*t*t*t + b;
  },
  easeOutStrong: function(t, b, c, d){  //减减速曲线
    return -c * ((t=t/d-1)*t*t*t - 1) + b;
  },
  easeBothStrong: function(t, b, c, d){  //加加速减减速曲线
    if ((t/=d/2) < 1) {
      return c/2*t*t*t*t + b;
    }
    return -c/2 * ((t-=2)*t*t*t - 2) + b;
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

残花月

暂无简介

0 文章
0 评论
467 人气
更多

推荐作者

束缚m

文章 0 评论 0

alipaysp_VP2a8Q4rgx

文章 0 评论 0

α

文章 0 评论 0

一口甜

文章 0 评论 0

厌味

文章 0 评论 0

转身泪倾城

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文