lynxerzhang / JSSkills

MIT License
0 stars 0 forks source link

CSS线性动画研究 #5

Open lynxerzhang opened 6 years ago

lynxerzhang commented 6 years ago

var root = document.getElementById("playground");

var e = createChild();
root.appendChild(e);

function createChild() {
    var e = document.createElement("div");
    e.style.position = "absolute";
    e.style.width = "50px";
    e.style.height = "10px";
    e.style.top = "10px";
    e.style.left = "500px";
    e.style.background = "blue";
    return e;
}

setTimeout(function(){
    var d = new DomAnimationX(e, {"x":-550 * .5, "duration":5000 * .5});
    d.add("complete", function(){
        setTimeout(function(){
            d = new DomAnimationX(e, {"x":-550, "duration":5000 * .5});
            f.add(d);
        }, 3000);
    })
    var f = new TickDomManager();
    f.add(d);
    f.start();
}, 0);

//使用transform对dom进行位移,同时又使用transition监听dom上的transfrom位移来达到线性动画的目的。
var TickDomManager = (function(){
    function TickDomManager(){
        this.domAnList = [];
        var self = this;
        this.tick = new Animation(function(t){
            self.tickCallback(t);
        });
    }
    var p = TickDomManager.prototype;
    p.start = function() {
        this.tick.start();
        var len = this.domAnList.length;
        var d;
        for(var i = 0; i < len; i ++){
            d = this.domAnList[i];
            if(d){
                d.start();
            }
        }
    }
    p.stop = function() {
        this.tick.stop();
        var len = this.domAnList.length;
        var d;
        for(var i = 0; i < len; i ++){
            d = this.domAnList[i];
            if(d){
                d.stop();
            }
        }
    }
    p.tickCallback = function(time) {
        var len = this.domAnList.length;
        var d;
        for(var i = 0; i < len; i ++){
            d = this.domAnList[i];
            if(d){
                d.tick(time);
            }
        }
    }
    p.add = function(domAn) {
        domAn.start();
        var self = this;
        domAn.add("complete", function(){
            self.remove(this);
            this.destroy();
        }.bind(domAn));  //bind 方法执行上下文环境
        this.domAnList.push(domAn);
    }
    p.remove = function(domAn) {
        var len = this.domAnList.length;
        var d;
        for(var i = len - 1; i >= 0; i --){
            d = this.domAnList[i];
            if(d && d == domAn){
                break;
            }
        }
        if(i >= 0 && i < len){
            this.domAnList.splice(i, 1);
        }
    }
    return TickDomManager;
})();

var DomAnimationX = (function(){
    function DomAnimationX(dom, data) {
        this.dom = dom;
        this.data = data;
        this.duration = data.duration;
        this.lifeDuration = this.duration;
        this.delay = data.delay || 0;
        this.watch = createEventDispatch();
    }
    var p = DomAnimationX.prototype;
    p.destroy = function() {
        this.dom = null;
        this.data = null;
        this.watch = null;
    }
    p.start = function() {
        Animation.setTransition(this.dom, "transform " + 
                        this.lifeDuration + "ms linear " + this.delay + "ms");
        Animation.setTransform(this.dom, "translateX(" + this.data.x + "px)");
        this.dispatch("start");
    }
    p.stop = function() {
        var d = this.data.x * ((this.duration - this.lifeDuration) / this.duration);
        Animation.setTransition(this.dom, "");
        Animation.setTransform(this.dom, "translateX(" + d + "px)");
        this.dispatch("stop");
    }
    p.tick = function(time) {
        if(this.lifeDuration <= 0){
            this.lifeDuration = 0;
            this.dispatch("complete");
            return;
        }
        this.lifeDuration -= time;
    }
    p.add = function(e, h) {
        this.watch.add(e, h);
    }
    p.remove = function(e, h) {
        this.watch.remove(e, h);
    }   
    p.dispatch = function(e) {
        this.watch.dispatch(e);
    }
    return DomAnimationX;
})();

var createEventDispatch = (function(){
    return function() {
        var watch = {};
        watch.listener = {};
        watch.add = function(e, h){
            var s = this.listener[e];
            if(!s){
                this.listener[e] = [h];
            }
            else{
                if(s.indexOf(h) < 0){
                    s.push(h);
                }
            }
        }
        watch.remove = function(e, h) {
            var s = this.listener[e];
            if(s){
                var len = s.length;
                if(arguments.length == 1){
                    s.length = 0;
                    s = null;
                    this.listener[e] = s;
                }else{
                    for(var i = len - 1; i >= 0; i--){
                        if(s[i] == h){
                            break;
                        }
                    }
                    if(i >= 0 && i < len){
                        s.splice(i, 1);
                    }
                }
            }
        }
        watch.dispatch = function(e){
            var s = this.listener[e];
            if(s){
                var len = s.length;
                var d;
                for(var i = len - 1; i >= 0; i --){
                    d = s[i];
                    d(e);
                }
            }
        }
        return watch;
    }
})();

var Animation = (function(){
    function Animation(callback){
        this.callback = callback;
        this.running = false;
                this.shouldKill = false;
                this.last = 0;
                this.now = 0;
    }
    Animation.setTransition = function(dom, trans) {
        dom.style.transition = trans;
        dom.style.webkitTransition = trans;
        dom.style.mozTransition = trans;
        dom.style.msTransition = trans;
        dom.style.oTransition= trans;
    }
    Animation.setTransform = function(dom, trans){
            dom.style.transform = trans;
            dom.style.webkitTransform = trans;
            dom.style.mozTransform = trans;
            dom.style.msTransform = trans;
            dom.style.oTransform = trans;
    }
        Animation.request =    (function(){
        return window.requestAnimationFrame   || 
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    || 
            window.oRequestAnimationFrame      || 
            window.msRequestAnimationFrame     || 
            function(callback){
                callback();
            };
    })();
    var p = Animation.prototype;
    p.start = function() {
        this.last = new Date().getTime();
        this.shouldKill = false;
        if (!this.running) {
            this.running = true;
            this.render();
        }
    };
    p.stop = function() {
        this.shouldKill = true;
        this.last = 0;
        this.now = 0;
    };
    p.toggle = function() {
        if (this.running) {
            this.stop();
        }
        else {
            this.start();
        }
    };
    p.render = function() {
        if(this.shouldKill) {
            this.shouldKill = false;
            this.running = false;
        }
        if (this.running) {
            this.now = new Date().getTime();
            if (this.callback) {
                this.callback(this.now - this.last);
            }
            this.last = this.now;
            var self = this;
            //Animation.request的调用需要如此,不然会报错,原因是该方法上下文执行环境被修改
            Animation.request.call(null, function(){
                self.render();
            });
        }
    };
    p.dispose = function() {
        this.stop();
        this.callback = null;
        this.running = false;
        this.shouldKill = false;
    };
    return Animation;
})();