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种缓动效果(二)


猜你喜欢
- mysql最常用的索引结构是btree(O(log(n))),但是总有一些情况下我们为了更好的性能希望能使用别的类型的索引。hash就是其中
- 1.首先生成array数组import numpy as npa = np.random.rand(5,5)print(a)结果:array
- 前言首先抛出几个问题:console.log(Boolean({}));console.log(Number([]));console.lo
- 方法1: 用SET PASSWORD命令 首先登录MySQL。 格式:mysql> set password for 用户名@loca
- 1.反变换法设需产生分布函数为F(x)的连续随机数X。若已有[0,1]区间均匀分布随机数R,则产生X的反变换公式为:F(x)=r, 即x=F
- 包 packageGo 包是 Go 语言的基本组成单元,一个 Go 程序就是一组包的集合,所有 Go 代码都位于包中Go 源码可以导入其他
- cli2去掉eslint检查器报错eslint在编写过程中及其严格,甚至单引号和双引号或者空格注释都会引起报错,导致项目无法正常运行因此,只
- 本文实例为大家分享了Python实点云分割k-means(sklearn),供大家参考,具体内容如下植物叶片分割import numpy a
- zip通常用于将两个列表合并在一起以同时进行迭代遍历注意:直接使用zip输出结果为<zip at 0x1d72cf30bc8>,
- 昨天给公司服务器重做了一下系统,遇到Asp附件无法上传,之前服务器上使用好好的,怎么重做了就不正常了,于是一番google,baidu,下面
- 1,System.ComponentModelSystem.ComponentModel 命名空间提供用于实现组件和控件的运行时和设计时行为
- 地图这期文章我们一起来看看地图是如何绘制的,如何在地图里面添加数据进行多维度的展示,下面我们一起来感受一下地图的魅力吧!&ldquo
- 题目:CSV格式清洗与转换描述附件是一个CSV格式文件,提取数据进行如下格式转换:
- 前言这段时间刚刚学习了一段时间的Python,加上自己是做iOS开发的,就想着用Python来做一个自动化打包,可以自动完成打包,上传到蒲公
- 前言本文主要给大家介绍了Go语言中函数new与make的使用和区别,关于Go语言中new和make是内建的两个函数,主要用来创建分配类型内存
- 一、merge函数用途pandas中的merge()函数类似于SQL中join的用法,可以将不同数据集依照某些字段(属性)进行合并操作,得到
- 文本的排版依据语言的不同会有一些格式上的要求,比如简体中文中类似逗号、分号等标点符号不会出现在一行的开头,对于英文来讲就是一个完整单词不会在
- 本文为大家分享了python爬取酷狗音乐排行榜的具体代码,供大家参考,具体内容如下#coding=utf-8from pymongo imp
- 最近有一个小项目,有如下的需求:将某几个源码文件夹进行打包,文件夹内有py文件、dll文件、exe文件等各种文件类型打包生成的安装包,在进行
- mysql是我们项目中非常常用的数据型数据库。但是因为我们需要在数据库保存中文字符,所以经常遇到数据库乱码情况。下面就来介绍一下如何彻底解决