视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
实现JavaScript动画的详细介绍
2020-11-27 20:24:09 责编:小采
文档

前言

现如今,许多页面上均有一些动画效果。适当的动画效果可以在一定程度上提高页面的美观度,具有提示效果的动画可以增强页面的易用性。

实现页面动画的途径有两种。一种是通过操作JavaScript间接操作CSS样式,每隔一段时间更新一次;一种是直接通过CSS定义动画。第二种方法在CSS3成熟之后被广泛采用。在本文中,我们讨论第一种方法的原理和实现。

JavaScript动画实现原理

首先我们需要知道两个重要的概念,动画时间进程和动画效果进程。

动画时间进程指从时间上看动画的完成度,是一个[0, 1]之间的数字。假设动画于时间戳t1开始,要在t2结束,当前时间戳为t,那么该动画目前的时间进程为(t-t1)/(t2-t1)。如果你不能理解,我建议你用纸笔画出来。理解这一概念对理解本文至关重要。

动画效果进程指被动画的属性值当前的增量。假设我们要将#el元素的CSS left 属性从100px变到200px,当前已经变到了130px,那么该动画目前的效果进程为130px - 100px = 30px

假设动画时间进程和动画效果进程都是线性的。那么如果知道了动画时间进程,一定可以得到动画效果进程。

根据这个解释,我们很快可以编写出一个线性的动画。

(function() {
 var begin, // 开始动画的时间
 el, start, end, duration; 
 var INTERVAL = 13;

 function now() {
 return (new Date).getTime();
 }

 /**
 * 执行一步动画(更新属性)
 */
 function _animLeft() {
 var pos = (now() - begin) / duration;
 if (pos >= 1.0) {
 return false;
 }
 return !!(el.style.left = start + (end - start) * pos);
 }

 /**
 * 对一个DOM执行动画,left从_start到_end,执行时间为
 * _duration毫秒。
 * 
 * @param {object} _el 要执行动画的DOM节点
 * @param {integer} _start left的起始值
 * @param {integer} _end left的最终值
 * @param {integer} _duration 动画执行时间
 */
 function animLeft(_el, _start, _end, _duration) {
 stopped = false;
 begin = now();
 el = _el;
 start = _start;
 end = _end;
 duration = _duration || 1000;

 var step = function() {
 if (_animLeft()) {
 setTimeout(step, INTERVAL);
 }
 };
 setTimeout(step, 0);
 }

 window.animLeft = animLeft;
 })();

 animLeft(
 document.getElementById('el'),
 100,
 200
 )

JSBin

easing

很多时候,我们需要的动画并非线性的。所谓非线性,从直观上看,就是动画速度随着时间会产生变化。那么如何实现变速的动画呢?

由前所述,我们知道通过控制动画的时间进程就相当于控制动画的效果进程。随着真实世界的时间进程推移,动画的时间进程跟着推移,从而控制动画的效果进程推移。那么,我们可以通过修改真实世界的时间进程和动画的时间进程间的映射关系,从而控制动画进程。如果你感到困惑,没关系,请看下图:

这是线性动画中,真实世界的时间进程和动画进程的映射关系。接下来,我们将其进行变换

这条曲线实际上是函数y = x * x的图像。可以看到,两个曲线的定义域和值域并没有变化。曲线的斜率就是动画的速率。接下来我们将两张图重叠在一起做一个对比。

在真实世界的时间进行到x0的时候,动画进程原本应该进行到y0,在进行变换之后,只进行到y1。到最后,百川归海,两条线交汇于点(1, 1)。这里,y = x * x是变换函数(easing function)。

我们修改一下上面的例子,让动画变成非线性的。

function ease(time) {
 return time * time;
 }

 /**
 * 执行一步动画(更新属性)
 */
 function _animLeft() {
 var pos = (now() - begin) / duration;
 if (pos >= 1.0) {
 return false;
 }
 pos = ease(pos);
 return !!(el.style.left = (start + (end - start) * pos) + "px");
 }

JSBin

我们可以在jQuery的代码中看到这样的函数。

jQuery.easing = {
 linear: function( p ) {
 return p;
 },
 swing: function( p ) {
 return 0.5 - Math.cos( p * Math.PI ) / 2;
 }
 };

因此,你可以往jQuery.easing里面添加easing function,使得jQuery支持新的动画速率控制方法。注意,easing function的定义域和值域必须都为[0, 1]。

 jQuery.easing.myEasing = function( p ) { return ... }

总结

JavaScript动画实质上也是通过操作CSS去执行动画。动画的时间进程可以决定动画的效果进程。通过操作真实世界的时间进程和动画的时间进程之间的关系,我们可以将线性动画变换成非线性的动画。

下载本文
显示全文
专题