什么是帧动画
- 所谓帧动画就是在“连续的关键帧”中分解动画动作,也就是在时间轴的每帧上逐帧绘制不同的内容,使其连续播放而成动画。
- 由于帧动画是一帧一帧的画,所以帧动画具有非常大的灵活性,几乎可以表现任何想表现的内容。
常见的帧动画方式
- GIF
- CSS3 animation
- Javascript
GIF和CSS3 animation实现帧动画的不足
- 不能灵活的控制动画的暂停和播放(GIF、CSS3 animation)
- 不能捕捉到动画完成的事件(GIF)
- 不能对帧动画做更加灵活的扩展(GIF、CSS3 animation)
JS实现帧动画的原理
- 如果有多张帧图片,用一个image标签去承载图片,然后定时改变image的src属性(不推荐,相当于请求了多张图片,会发送多个http请求)
- 把所有动画关键帧绘制在一张图片里,把图片作为元素的backgroud-image,定时改变元素的background-position属性(推荐,只有一个http请求)
eg:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>JS实现帧动画</title>
<style type="text/css">
#rabbit {
width: 102px;
height: 80px;
}
</style>
</head>
<body>
<div id="rabbit"></div>
<script type="text/javascript">
// 做一个兔子不停原地奔跑的帧动画,每一帧都放在一张大图里
var rabbit = document.getElementById("rabbit");
// 获取每一帧在图片中对应的位置
var positions = ['0 -854', '-174 -852', '-349 -852', '-524 -852', '-698 -852', '-873 -848'];
// 设置兔子的背景图片
rabbit.style.backgroundImage = 'url(rabbit.png)';
rabbit.style.backgroundRepeat = 'no-repeat';
// 每隔一段时间改变背景图片的位置
var index = 0;
function run() {
var position = positions[index].split(' ');
rabbit.style.backgroundPosition = position[0] + 'px ' + position[1] + 'px';
index++;
if (index >= positions.length) {
index = 0;
}
setTimeout(run, 80);
}
run();
</script>
</body>
</html>
问题:在用setTimeout模拟setInterval时,怎么清除定时器?菜鸟上说要在全局定义定时器,但是不是递归调用的吗?能清除所有的定时器吗?感觉只能清除一个呀。
ps:这是从慕课网上学的js帧动画课程,后面还有教你怎么去封装这样一个帧动画,虽然看懂了,但是我什么时候也能写出这样的代码来呀,逻辑清晰,复用性强,鲁棒性强。
他从需求分析->编程接口->调用方式->代码设计这四个步骤一步一步来,但是我都不知道要定义哪些接口。。。
需求分析
- 支持图片预加载(图片的加载是一个异步过程,如果在动画执行过程中图片还没被下载下来的话,会导致动画的前几帧都是空白图片,所以我们要保证动画执行的时候图片是已经被下载好的)
- 支持两种动画播放方式,及自定义每帧动画
- 支持单组动画控制循环次数(可支持无限次)
- 支持一组动画完成,进行下一组动画
- 支持每个动画完成后有等待时间
- 支持动画暂停和继续播放
- 支持动画完成后执行回调函数
编程接口
-
loadImage(imglist) //预加载图片
-
changePosition(ele,positions,imageUrl) //通过改变元素的background-position实现动画
-
changeSrc(ele,imglist) //通过改变image元素的src
-
enterFrame(callback) //每一帧动画执行的函数,相当于用户可以自定义每一帧动画的callback
-
repeat(times) //动画重复执行的次数,times为空时表示无限次
-
repeatForever() //无限重复上一次动画,相当于repeat(),更友好的一个接口吧
-
wait(time) //每个动画执行完后等待的时间
-
then(callback) //动画执行完成后的回调函数
-
start(interval) //动画开始执行,interval表示动画执行的间隔
-
pause() //动画暂停
-
restart() //动画从上一次暂停处重新执行
-
dispose() //释放资源
调用方式
-
支持链式调用,我们期望动词的方式描述接口,调用方式如下:
var animation = require("animation"); var demoAnimation=animation().loadImage(images).changePosition(ele,positions).repeat(2).then(function(){ /*动画执行完成后调此函数*/ }); demoAnimation.start(80);
代码设计
-
我们把“图片预加载->动画执行->动画结束”等一系列操作看成一条任务链(数组)
-
任务链有两种类型的任务:a.同步执行完毕的;b.异步定时执行的(通过计时器或者raf)。
-
-
记录当前任务链的索引
-
每个任务执行完毕后,通过调用next方法,执行下一个任务,同时更新任务链索引值