前端动画库设计及实现
作者寄语:该文章讲解动画库设计思想和具体实现方式,欢迎大家到源码查看并提出意见。
一、Usage
npm install io-animation
二、测试case
- 查看百度脑图附件
三、测试页面
四、设计目的
- 功能
- 提高动画性能,css3 transition实现;
- 支持动画播放/暂停;
- 兼容
- 不支持transition,通过setTimeout实现;
- 写法
- 支持链式写法;
- 支持非链式写法;
- 执行顺序
- 支持串行动画;
- 支持并行动画;
- 支持串行&并行结合动画(JQuery&Zepto不支持);
- 支持多dom动画(通过类选择器,默认为并行);
- 类型
- 支持普通动画;
- 支持transform动画;
- 不支持keyframe动画;
- 回调
- 支持串行回调;
- 支持并行回调;
- 支持并行动画全部执行完成的回调;
五、案例
单对象串行;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18animate(propDomCallbackBtn1, {
width: "70%"
}, {
duration: 1000,
easing: "ease",
cb: function () {
console.log("串行1");
}
})
.animate(propDomCallbackBtn2, {
height: 200
}, {
duration: 3000,
easing: "ease",
cb: function () {
console.log("串行2");
}
});单对象并行;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24animate(propDomCallbackBtn1, {
width: "70%"
}, {
duration: 1000,
easing: "ease",
delay: 2000,
isAsync: 1,
cb: function () {
console.log("并行1");
}
})
.animate(propDomCallbackBtn2, {
height: 200
}, {
duration: 3000,
easing: "ease",
isAsync: 1,
cb: function () {
console.log("并行2");
}
})
.endAnimaion(function() {
console.log("并行动画全部执行完成");
});单对象串行&并行;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32animate(propDomCallbackBtn1, {
width: "70%"
}, {
duration: 1000,
easing: "ease",
isAsync: 1,
cb: function () {
console.log("并行1");
}
})
.animate(propDomCallbackBtn2, {
height: 200
}, {
duration: 3000,
easing: "ease",
isAsync: 1,
cb: function () {
console.log("并行2");
}
})
.start(function() {
console.log("并行动画全部执行完成");
})
.animate(propDomCallbackBtn2, {
height: 200
}, {
duration: 3000,
easing: "ease",
cb: function () {
console.log("串行1");
}
});多对象并行;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49animate(propDomCallbackBtn1, {
width: "70%"
}, {
duration: 1000,
easing: "ease",
delay: 2000,
isAsync: 1,
cb: function () {
console.log("串行1");
}
})
.animate(propDomCallbackBtn1, {
height: 200
}, {
duration: 3000,
easing: "ease",
isAsync: 1,
cb: function () {
console.log("串行1");
}
})
.start(function() {
console.log("并行动画全部执行完成1");
});
animate(propDomCallbackBtn2, {
width: "70%"
}, {
duration: 1000,
easing: "ease",
delay: 2000,
isAsync: 1,
cb: function () {
console.log("并行3");
}
})
.animate(propDomCallbackBtn2, {
height: 200
}, {
duration: 3000,
easing: "ease",
isAsync: 1,
cb: function () {
console.log("并行4");
}
})
.start(function() {
console.log("并行动画全部执行完成2");
});六、参数
dom: dom元素,可以是一个元素,也可以是一个dom数组,不能为空;
property: 属性对象,不能为空;
opt: 动画相关参数
- opt.duration: 动画持续时间,如果不设置默认为0.4s;
- opt.easing: 动画执行的形式, 如”ease, ease-in, ease-out, ease-in-out, linear, cubic-bezier”, 默认为”linear”;
- opt.callback: 回调函数,在动画执行完成之后执行,分为两种,一种为单个动画执行完成之后的回调,另一种是所有并行动画执行完成的回调;
- opt.delay: 延迟时间,如果不设置默认为0s;
- opt.isAsync: 是否动画是并行,0为串行,1为并行;
七、注意点
- 动画需要调用start才能开始执行;
- 非链式写法是创建了多个对象,所以表现为并行动画,不能通过isAsync控制为串行;
八、设计方案概述
- 存储方案:单个对象串并行动画通过一个队列来进行存储;
- 多对象动画方案:通过生成多个对象来各自管理;
- 单对象动画方案:每个对象的串并行动画通过队列存储,以”#”分隔,每两个”#”之间代表一组并行动画,如果只有一个,则表现为串行形式;
九、详细设计方案
关键类
入口类:每次单独(串行方式)调用一个
animate
函数时都会经过该类,他的主要作用是生成一个新的动画对象,并返回动画管理类,从而支持并行工作和链式调用,下面是其实现:动画管理类:该类是管理每个对象生成的动画,包含三个主要属性和方法;
isRuning
:当前动画执行状态,执行中/执行完成;asyncQueue
:动画队列,存储串并行动画对象;endCallback
:并行动画全部执行完成的回调队列;animate(ele, property, opt)
:动画开始入口;start(fn)
:结束并行动画,其中可以传入回调;stop()
:停止当前动画;
动画方案时序图:粗略的分为这几个块,starUML不太会用,有的生命周期可能画的不太对,先将就着看看
- 第一步:首先一个动画对象进入之后会先初始化一个动画对象;
- 第二步:初始化后进入动画管理中心,进行单个动画管理;
- 第三步:动画正式开始之前会对动画的参数进行筛选和处理,比如集合属性的单位(
'px'
)处理,浏览器vendor处理('webkit', 'moz', 'ms', 'o', 'Webkit', 'Moz', 'O'
),是否支持transition处理等; - 第四步:创建动画对象,并将其加入动画队列中;
- 第五步:开始执行动画;
- 第六步:动画执行完成之后进行该动画回调;
- 第七步:所有回调都执行完成之后进行并行动画终止回调的执行;
- 第八步:如果队列中仍然存在动画对象,执行下一个,跳转至步骤一;
十、设计注意点
- transitionend多次执行:transitionend执行时机是每一个属性执行完成就会执行,所以你的动画有几个属性,他就会执行几次。这个比较好解决,在执行时remove了transitionend事件监听即可;但是如果多个并行动画执行在一个dom上时就蛋疼了,单纯remove监听是做不到的,可以通过判断动画delay+duration来判断是否是当前动画;
- 不支持transition怎么办:该实现方案采用的方式是,transition和setTimeout会同时执行,在一次回调处理时会clearTimeout和remove监听,从而做到双保险的作用;
十一、License
MIT License
以上是大概的设计思路,具体可以在上面链接中深入到代码中查看!