移动端重构实战系列4——进入离开动画
”本系列教程为实战教程,是本人移动端重构经验及思想的一次总结,也是对sandal及sheral UI的一次全方位剖析,首发在imweb和w3cplus两大站点及“前端Talk”微信公众号,其余所有标注或没有标注来源的均为转载。“
——imweb 结一
进入离开动画
在sandal的_animation.scss
中我们定义了fade-in/out
, shrink-in/out
, up-in/out
, down-in/out
, left-in/out
, right-in/out
六组基础动画,下面我们以fade-in/out
为例说明如何使用:
直接调用mixin:
@include animation-fade-in;
@include animation-fade-out;
编译出的CSS为:
.fade-in, .fade-out {
-webkit-animation-duration: 0.3s;
animation-duration: 0.3s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.fade-in {
-webkit-animation-name: fadeIn;
animation-name: fadeIn;
}
@-webkit-keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.fade-out {
-webkit-animation-name: fadeOut;
animation-name: fadeOut;
}
@-webkit-keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
当然为了扩展,mixin还定义了两个参数:animation-fade-in($className: fade, $from: 0)
,animation-fade-out($className: fade, $to: 0)
,第一个表示要用的class名字(会自动补上in/out
),第二个表示opacity
值(from
为起始,to
为结束)
现在CSS的动画class已经有了,接下来就是用JS把这两个class分别添加到进入和离开的时候。
es6 封装动画进入离开类
export class AnimateInOut {
constructor({ele, className, inCallback, outCallback}) {
this.ele = ele.nodeType === 1 ? ele : document.querySelector(ele);
this.inClass = className + '-in'; // 加上in表示进入class
this.outClass = className + '-out'; // 加上out表示离开class
this.inCallback = inCallback; // 进入动画结束后回调函数
this.outCallback = outCallback; // 离开动画结束后回调函数
this.animationend = this.whichEndEvent(); // 使用animationend事件
this.endBind = this.end.bind(this); // 绑定this
}
// 进入
enter() {
this.ele.classList.add(this.inClass);
// animation动画结束之后,移除该class
this.ele.addEventListener(this.animationend, this.endBind);
}
// 离开
leave() {
this.ele.classList.add(this.outClass);
// animation动画结束之后,移除该class
this.ele.addEventListener(this.animationend, this.endBind);
}
// 动画结束事件处理函数
end() {
var ele = this.ele,
eleClassList = ele.classList,
isIn = eleClassList.contains(this.inClass), // 进入
isOut = eleClassList.contains(this.outClass); // 离开
ele.removeEventListener(this.animationend, this.endBind);
if(isIn) {
eleClassList.remove(this.inClass);
this.inCallback && this.inCallback();
}
if(isOut) {
eleClassList.remove(this.outClass);
this.outCallback && this.outCallback();
}
}
// 判断end事件,可独立为一个基础功能
whichEndEvent() {
var k
el = document.createElement('div');
var animations = {
"animation" : "animationend",
"WebkitAnimation": "webkitAnimationEnd"
}
for(k in animations) {
if(el.style[k] !== undefined) {
return animations[k];
}
}
}
}
注意这里我们采用的
animation
动画,而不是transition
动画,因为transition动画从none到block的时候,直接添加动画的class是不会有动画效果的(除非使用回调函数或promise),而animation动画从none到block的时候添加动画class是可以的。这里不想设计得太复杂,所以直接使用animation动画
调用
function leaveEnd() {
console.log('hello the world');
}
var animateInOut = new AnimateInOut({ele: $el, className: 'fade', outCallback: leaveEnd});
// 进入的时候调用
animateInOut.enter();
// 离开的时候调用
animateInOut.leave();
本系列教程未完待续,正在码字中...
如需转载,烦请注明出处:http://www.w3cplus.com/mobile/sandal-parts-4.html