javascript 45种缓动效果(一)

作者:司徒正美 来源:司徒正美blog 时间:2009-09-19 18:30:00 

缓动,学名为Tween,缓冲移动的简称。要想页面内容切换起来舒服,就使用淡入淡出特效,要想让页面元素动起来自然,就要使用缓动效果。这两个混合起来,可以衍生多种特效的。感谢Flash开发人员为我们做了那么多先行研究,我们直接把它们拆出来装在各种菜单与相册中。我们先从最简单的东西做起,加速与减速。

既然是缓动,它就一定涉及以下概念:距离,时间与速度。我们可以想象存在一条直线L,点A与点B就是L的起点与终点,有一个点C在直线L上移动,从点A到点B。所需的时间通常都是未知,但速度我们一定要制定。看下面的图,我们想让绿色的方块在淡紧色的滑动带上移动。滑动带左上角就相当于点A,右上角就相当于B点,方块的左上角就相当于点C,移动距离为两者的宽度之差。由于我们移动的物体是存在宽度,也就是说点C永远不可能与点B重合。但一个准确的目的地(为了方便,我们把它称之为点D)是必须的,我们一定要计算它出来。因为在加速运动中,点C随时可能超过点D,当点超过它时,我们就要终止此移动,并把点C拉回到点D上。


为了获取它们在页面上的坐标与尺寸,getCoords()与getStyle()又到出场时间了。对不起,我实在没有意思来炫耀我的函数。更何况getStyle()被砍去了不少东西,威力没有以前那么强大。

//辅助函数1  var getCoords = function(el){    var box = el.getBoundingClientRect(),    doc = el.ownerDocument,    body = doc.body,    html = doc.documentElement,    clientTop = html.clientTop || body.clientTop || 0,    clientLeft = html.clientLeft || body.clientLeft || 0,    top  = box.top  + (self.pageYOffset || html.scrollTop  ||  body.scrollTop ) - clientTop,    left = box.left + (self.pageXOffset || html.scrollLeft ||  body.scrollLeft) - clientLeft    return { 'top': top, 'left': left };  };  //辅助函数2  var getStyle = function(el, style){    if(!+"\v1"){      style = style.replace(/\-(\w)/g, function(all, letter){        return letter.toUpperCase();      });      var value = el.currentStyle[style];      (value == "auto")&&(value = "0px" );      return value;    }else{      return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)    }  }

那么我们怎么移动呢?在javascript只有让它变为绝对定位对象,给它的top与left赋值。它就会立即移动到相应的坐标上。由于javascript处理位置变化太有效率,根本不可能让你有“移动”的感觉,感觉是直接从点C直接跳到点D。我们必须让物体每移动一点点,就停一下,让眼睛有个残影。根据人眼睛的视觉停留效应,若前一幅画像留在大脑中的印象还没消失,后一幅画像就接踵而至,而且两副画面间的差别很小,就会有“动”的感觉。

那么停留多么毫秒最合适呢?我们不但要照顾人的眼睛,还要顾及一下显示器的显示速度与浏览器的渲染速度。根据外国的统计,25毫秒为最佳数值。其实,这个数值我们应该当作常识来记住。联想一下,日本动画好像有个规定是1秒30张画,中国的,比较垃圾,是1秒24张。用1秒去除以张数,就得到每张停留的时间。日本的那个27.77毫秒已经很接近我们的25毫秒了,因为浏览器的渲染速度明显不如电视机的渲染速度,尤其是IE6这个拉后腿的。要实现加速度,就是让它每次移动快一点点,让上一次移动的距离乘以一个大于1的数便可。

//辅助函数3,相当于$(),不用$符号命名是因为博客园在用JQuery,会引起命名冲突  //我新一代查代元素的方法,拥有缓存能力  var cache = []  var _ = function(id){    return cache[id] || (cache[id] = document.getElementById(id));  }  //主函数:加速移动  var accelerate= function(el){    el.style.position = "absolute";    var begin =  getCoords(el).left,    distance = parseFloat(getStyle(_("taxiway"),"width")) - parseFloat(getStyle(el,"width")),    end = begin + distance,    speed = 10;//第一次移动的速度,单位px/ms,隐式地乘以1ms    (function(){      setTimeout(function(){        el.style.left = getCoords(el).left + speed + "px";//移动        speed *= 1.5;//下一次移动的距离        if(getCoords(el).left >= end){          el.style.left = end + "px";        }else{                  setTimeout(arguments.callee,25);//每移动一次停留25毫秒        }      },25)    })()  }

明白了加速,减速就好办了。我们给第一次移动的距离一个很大的数,往后每次减少一点点,换言之乘以一个小于1的数。但这里有个注意点,如果有一次,它移动的距离少于1px怎么办?!它再往后也是少于1px。浏览器就会忽略这个值,当作0来处理。这样一来,它就会停在中途不动了。为了防止这样可怕的事发生,我们利用Math.ceil来确保其最小移动距离为1px,哪怕最后的匀速移动也要抵达终点。

//主函数:减速移动  var decelerate = function(el){    el.style.position = "absolute";    var begin =  getCoords(el).left,    distance = parseFloat(getStyle(_("taxiway"),"width")) - parseFloat(getStyle(el,"width")),    end = begin + distance,    speed = 100;//第一次移动的速度,单位px/ms,隐式地乘以1ms    (function(){      setTimeout(function(){        el.style.left = getCoords(el).left + speed + "px";//移动        speed = Math.ceil(speed * 0.9);//下一次移动的距离        if(getCoords(el).left <= end){          el.style.left = end + "px";        }else{                  setTimeout(arguments.callee,25);        }      },25)    })()  }

现在函数的功能还很弱,主要是由于在抽象与制定上有所欠缺,如果克服这些缺点并配合Robert Penner大神的缓动公式,我们就可以搞出花样繁多的缓动效果来。而这正是下部分要讲解的,敬请期待,也希望大家多多留言支持。

阅读下一篇:javascript 45种缓动效果(二)

标签:JavaScript,缓动,Tween,特效
0
投稿

猜你喜欢

  • Python初识逻辑与if语句及用法大全

    2023-11-21 16:17:24
  • python 两个一样的字符串用==结果为false问题的解决

    2023-01-24 08:30:59
  • mysql性能的检查和调优方法

    2009-05-17 09:21:00
  • Python中and和or如何使用

    2022-04-27 18:01:49
  • Python3逻辑运算符与成员运算符

    2021-03-29 18:59:14
  • Python日期时间Time模块实例详解

    2023-11-07 07:26:34
  • js实现做通讯录的索引滑动显示效果和滑动显示锚点效果

    2024-04-16 09:23:00
  • Go语言copy()实现切片复制

    2024-05-25 15:12:43
  • Python实现从SQL型数据库读写dataframe型数据的方法【基于pandas】

    2024-01-18 07:02:59
  • Python编程实现的简单Web服务器示例

    2023-01-14 02:00:40
  • mysql8.0忘记密码修改与net命令服务名无效问题

    2024-01-21 10:23:57
  • MySQL 4.0 升级到mysql 5.0的方法

    2024-01-18 10:07:12
  • 微信小程序搭建及解决登录失败问题

    2023-06-28 09:51:49
  • 基于python写个国庆假期倒计时程序

    2022-06-04 20:35:32
  • Python数据可视化:顶级绘图库plotly详解

    2021-04-09 19:37:13
  • 从pandas一个单元格的字符串中提取字符串方式

    2022-10-14 21:24:35
  • Python 中 f-Strings 的作用

    2022-12-04 11:44:55
  • Laravel框架实现发送短信验证功能代码

    2024-05-03 15:29:08
  • Python运行DLL文件的方法

    2021-12-25 15:23:21
  • pytorch中的自定义数据处理详解

    2023-08-21 09:31:35
  • asp之家 网络编程 m.aspxhome.com