博客
关于我
分享一个即插即用的私藏缓动动画JS小算法
阅读量:390 次
发布时间:2019-03-05

本文共 4365 字,大约阅读时间需要 14 分钟。

一、动画算法的故事

甜如初恋

人是一种恋旧的动物,即使过了很多年,即使小屁孩已经学会了打酱油,但是,这心中那,总是时不时会想起初恋的那个她,虽未提及,但在心里。

如果动画算法是恋人的话,那也有类似的故事。

当年还是个青涩男孩的时候,什么都是懵懵懂懂,实现效果要么干巴巴,要么拿来主义。直到一次偶然的邂逅,一次冥冥中注定的邂逅,我遇到了她,她是如此简单可爱,让我过目不忘。于是,一下子自己仿佛打开了一扇新的窗,有了她的相伴,实现的效果不再是干巴巴的,而是开始有了绚丽的色彩,开始有了灵动的气息。

后来,我成长了,接触了越来越多的外面的世界,遇到了越来越多是动画算法,这些算法确实很美,实现的效果更佳的炫丽,甚至将她们全部收纳整理成了后宫家族(可参考之前“”这篇文章),但是,实际开发的时候,使用的最多的还是最初的那个她,不仅是因为她给我带来了很多美好的回忆,更重要的是这么多年过去了,她一直保持着那份简单,和外面的那些妖艳*货完全不一样。

而这个相伴自己最久,最无法忘怀的、使用最多的她就是本文要分享的私藏的动画小算法。

虽然标准全面且强大,但是,里面的公式略复杂,根本就记不住,每次使用都要去找一下,甚是麻烦。

而且,平时开发,绝大多数场景下,我们并不需要是那种弹来弹去的浮夸效果,有点缓动就可以,本文要分享的动画小算法就是一个简单的缓动小算法。

二、即插即用的缓动小算法

原理如下:

假设要从数值A变化到数值B,如果是线性运动,则每次移动距离是一样;如果是缓动,每次移动距离不一样。那如何才能不一样呢?很简单,按比例移动就可以。

例如:每次移动剩余距离的一半。

对吧,超容易理解的。

比方说:你和初恋之间距离是64,每秒移动一半,则,你们之间的距离下一秒就是32, 再下一秒就是16,然后8,然后4,然后2,然后1,然后……你们就在一起了。你们在一起的这个过程就是一个典型的先快后慢的缓动运动过程,如下示意图:

位置移动标注示意图

用一个简单的公式表示就是:

A = A + (B - A) / 2

翻译一下就是:

我下一秒的位置 = 现在位置 + 现在和初恋之间距离的一半

是不是很好理解。

而上面的A = A + (B - A) / 2就是本文要介绍的即插即用的缓动小算法。

当然要实际使用还是需要做一点点的处理的,首先,既然是运动,那就离不开定时器,我们可以使用requestAnimationFrame,对于不支持的浏览器,可以使用下面的兼容代码:

// requestAnimationFrame的兼容处理if (!window.requestAnimationFrame) {    requestAnimationFrame = function(fn) {        setTimeout(fn, 17);    };	}

下面我们套用一个简单的实例,看看这个算法是如何应用的,就是非常常见的返回顶部效果。很多网站返回顶部要么直接“啪”到顶部,要么动画按部就班没有灵性,这里演示下如何使用寥寥数行代码,实现带缓动的返回顶部效果。点击下面的按钮即可看到返回顶部效果:

点击我返回顶部

 

点击按钮执行的是下面的backToTop()方法:

// 滚动到顶部缓动实现// rate表示缓动速率,默认是2var backToTop = function (rate) {    var doc = document.body.scrollTop? document.body : document.documentElement;    var scrollTop = doc.scrollTop;        var top = function () {        scrollTop = scrollTop + (0 - scrollTop) / (rate || 2);                // 临界判断,终止动画        if (scrollTop <= 1) {            doc.scrollTop = 0;            return;        }        doc.scrollTop = scrollTop;        // 动画gogogo!        requestAnimationFrame(top);        };    top();};

其中,代码的核心是:

scrollTop = scrollTop + (0 - scrollTop) / (rate || 2);

scrollTop表示公式的A, 滚动到顶部滚动高度是0,因此,上面的0,实际上就是公式的B, 而公式中的2表示缓动速率,实际开发的时候是可以灵活调整的,缓动速率范围是1到无穷大,速率值越小,运动越快。比如说上面的返回顶部效果,我们把缓动速率改成4,点击下面的按钮感受效果:

点击我执行backToTop(4)

可以明显感觉到,返回顶部使用的时间变长了,速度变慢了,缓动体验也更明显了。

等比例靠近理论上最终只会无穷靠近,并不会真正的相等,也就是动画永远没有结束的时候,所以说需要做一个临界判断,也就是距离小到一定数目的时候,直接等于目标值,并终止动画。例如,上面的返回顶部,就是当距离顶部滚动高度小于1的时候,直接返回顶部,并终止动画。

if (scrollTop < 1) {    doc.scrollTop = 0;    return;}

我们最近刚上线不久的新版的(https://m.qidian.com)的返回顶部效果就是使用的这个缓动小算法。

返回顶部截图示意

当然,使用这个动画小算法的地方不止这一个,比方说首页最近阅读的小球是可以移动的,惯性运动动画效果就是用的该算法,还是书籍阅读页面水平看书模式时候移来移去的翻页效果,也是此算法;垂直模式时候点击翻屏也是该算法等等。

用得非常多,因为简单,不需要查资料直接可以写出来,只要记住“等比例靠近”这个词,就不会忘记该怎么实现,永远忘不了的初恋就是这种感觉。

更新于2019-11-28

实际开发时候有时候不是滚动到顶部,而是任意位置,于是对上面方法改造了下:

// 滚动到顶部缓动实现// rate表示缓动速率,默认是2window.scrollTopTo = function (top, callback) {    var scrollTop = document.scrollingElement.scrollTop;    var rate = 2;    var funTop = function () {        scrollTop = scrollTop + (top - scrollTop) / rate;        // 临界判断,终止动画        if (Math.abs(scrollTop - top) <= 1) {            document.scrollingElement.scrollTop = top;            callback && callback();            return;        }        document.scrollingElement.scrollTop = scrollTop;        // 动画gogogo!        requestAnimationFrame(funTop);    };    funTop();};

其中:

top

必需。Number。垂直方向希望滚动的位置。

callback

必需。Function。滚动到指定位置时候的回调方法。

滚动速率内置了,是2,因为实际开发速率调整并不常用。

总之,经过改造后,滚动到顶部的这个方法变得实用多了。

三、即插即用的缓动小算法变身

如果项目很多地方使用该算法,每次都写一遍requestAnimationFrame和边界判断是很啰嗦的,于是,我们可以把算法变个身,例如下面这样:

Math.easeout = function (A, B, rate, callback) {    if (A == B || typeof A != 'number') {        return;        }    B = B || 0;    rate = rate || 2;        var step = function () {        A = A + (B - A) / rate;                if (A < 1) {            callback(B, true);            return;        }        callback(A, false);        requestAnimationFrame(step);        };    step();};

其中:

  • A是起始位置;
  • B是目标位置;
  • rate是缓动速率;
  • callback是变化的位置回调,支持两个参数,valueisEnding,表示当前的位置值(数值)以及是否动画结束了(布尔值);

于是,我们的返回顶部效果可以这么使用:

var doc = document.body.scrollTop? document.body : document.documentElement;Math.easeout(doc.scrollTop, 0, 4, function (value) {    doc.scrollTop = value;});

点击我执行Math.easeout返回顶部

 

可以看到效果是一样的棒棒哒。

更关键点是我们的算法可以全局无限制重复利用啦!

四、结束语

本文有3个按钮,每个按钮点击都会有带缓动的返回顶部的效果,如果您发现您的浏览器按钮点击没效果,或者没按钮,则多半您访问的不是原出处。

根据我自己的猜测,中,应该有类似本文的小算法的,应该就是某个easeOut方法。但是,具体实现上还是会有一些差异的,Tween.js是基于时间来做算法的,而本文的Math.easeout算法是基于缓动速率的,最终的时间是不固定的,受起始和终止位置的距离的影响,也正是这个原因,本文的缓动动画算法更好理解更容易记忆,因为现实世界距离是真实的容易感知的,时间是虚幻的无法捕捉的,正好和本文的算法距离驱动而非时间驱动相映射,容易形成共识。

恩,就说这么多吧。

感谢阅读,欢迎交流,更欢迎大力分享,你瞧,我把珍藏的初恋都分享出来了,还不点赞分享支持下。

转载地址:http://tlpwz.baihongyu.com/

你可能感兴趣的文章
mysqli
查看>>
MySQLIntegrityConstraintViolationException异常处理
查看>>
mysqlreport分析工具详解
查看>>
MySQLSyntaxErrorException: Unknown error 1146和SQLSyntaxErrorException: Unknown error 1146
查看>>
Mysql_Postgresql中_geometry数据操作_st_astext_GeomFromEWKT函数_在java中转换geometry的16进制数据---PostgreSQL工作笔记007
查看>>
mysql_real_connect 参数注意
查看>>
mysql_secure_installation初始化数据库报Access denied
查看>>
MySQL_西安11月销售昨日未上架的产品_20161212
查看>>
Mysql——深入浅出InnoDB底层原理
查看>>
MySQL“被动”性能优化汇总
查看>>
MySQL、HBase 和 Elasticsearch:特点与区别详解
查看>>
MySQL、Redis高频面试题汇总
查看>>
MYSQL、SQL Server、Oracle数据库排序空值null问题及其解决办法
查看>>
mysql一个字段为空时使用另一个字段排序
查看>>
MySQL一个表A中多个字段关联了表B的ID,如何关联查询?
查看>>
MYSQL一直显示正在启动
查看>>
MySQL一站到底!华为首发MySQL进阶宝典,基础+优化+源码+架构+实战五飞
查看>>
MySQL万字总结!超详细!
查看>>
Mysql下载以及安装(新手入门,超详细)
查看>>
MySQL不会性能调优?看看这份清华架构师编写的MySQL性能优化手册吧
查看>>