结一

6个月前
  • 1580

    浏览
  • 1

    评论
  • 0

    收藏

移动端重构实战系列4——进入离开动画

本文作者:imweb 结一 原文出处:imweb社区 未经同意,禁止转载

”本系列教程为实战教程,是本人移动端重构经验及思想的一次总结,也是对sandalsheral UI的一次全方位剖析,首发在imwebw3cplus两大站点及“前端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];
            }
        }
    }
}

PS:注意这里我们采用的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();

PS:本系列教程未完待续,正在码字中...

1 条评论