代码改变世界

Javascript动画系列之 —— lightbox实现(二)

2013-04-26 21:02  MoltBoy  阅读(1445)  评论(1编辑  收藏  举报

  上次帖子里详细描述了lightbox实现思路,本想将整个原生的lightbox源码放出来,但是觉得留点思考的余地更好。

  本文中就贴上淡入淡出和滑动的JS原生代码,通过测试,能兼容IE8、Firefox、Chrome。

function bind(fn, context){  //函数绑定,传递context上下文
    var args = Array.prototype.slice.call(arguments, 2);
    return function(){
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);  //柯里化参数
        return fn.apply(context, finalArgs);
    };
}
var addEvent = function(ele, event, fn){  //添加事件兼容
    ele.addEventListener ? ele.addEventListener(event, fn, false) :
    ele.attachEvent ? ele.attachEvent("on" + event, fn) : (ele["on" + event] = fn);
};
var animation = {
    config: {    //参数
        interval: 17,
        show: true,
        distance: 0,
        distanceW: 0                
    },
    calculate: function(strSpeed, height, width){    //几种模式不同的算法
        var speed = this.speedFn(strSpeed),
            i = this.config.interval;
        return typeof height === "undefined" && typeof width === "undefined" ?
        {
            frames: (speed - 0) / i,
            step: i / (speed - 0)
        } : {
            frames: (speed - 0) / i,
            step: i * height / (speed - 0),
            stepw: i * width / (speed - 0)
        }
    },
    trim: function(str){    //去掉两头空格,测试过速度相比其他trim方法快很多
        //return str.replace(/^\s*/, '').replace(/\s*$/, '');
        return str.replace(/^\s*|\s*$/, '');
    },
    speedFn: function(strSpeed){
        strSpeed = (this.trim(strSpeed)).toLowerCase();
        switch(strSpeed){
            case "fastest":
                return 400;
            case "faster":
                return 500;
            case "fast":
                return 600;
            case "normal":
                return 700;
            case "slow":
                return 800;
            case "slower":
                return 900;
            case "slowest":
                return 1000;
            case "debug":
                return 2000;
            default:
                return 500;
        }
    },
    fadeOut: function(ele, strSpeed){                    
        var count = 0, c = this.config, s = ele.style,
            m$ = this.calculate(strSpeed);
        ele.currentStyle ? (s.filter = "alpha(opacity=100)") : s.opacity = 1;

        try{
            setTimeout(function(){
                count++;
                if(count > m$.frames){                            
                    ele.currentStyle ? (s.filter = "alpha(opacity=0)") : s.opacity = 0;
                }else{
                    if(!ele.currentStyle){
                        s.opacity -= m$.step;
                    }else{
                        var f = parseFloat(ele.currentStyle.filter.match(/\d+/).toString());
                        f -= m$.step * 100;
                        s.filter = "alpha(opacity=" + f + ")";
                    }
                    setTimeout(arguments.callee, c.interval);
                }
            }, c.interval); 
        }catch(ex){
            console.log("fadeOut error, " + ex.message);
        }
        c.show = false;
    },
    fadeIn: function(ele, strSpeed){
        var count = 0, c = this.config, s = ele.style,
            m$ = this.calculate(strSpeed);
        ele.currentStyle ? (s.filter = "alpha(opacity=0)") : s.opacity = 0;

        try{
            setTimeout(function(){
                count++;
                if(count > m$.frames){                            
                    ele.currentStyle ? (s.filter = "alpha(opacity=100)") : s.opacity = 1;
                }else{
                    if(ele.currentStyle){
                        var f = parseFloat(ele.currentStyle.filter.match(/\d+/).toString());
                        f += m$.step * 100;
                        s.filter = "alpha(opacity=" + f + ")";
                    }else{
                        s.opacity = parseFloat(s.opacity) + m$.step;
                    }
                    setTimeout(arguments.callee, c.interval);
                } 
            }, c.interval); 
        }catch(ex){
            console.log("fadeIn error, " + ex.message);
        }
        c.show = true;
    },
    fadeToggle: function(ele, strSpeed){    //淡入淡出切换
        var self = this;
        setTimeout(function(){                        
            self.config.show ? self.fadeOut(ele, strSpeed) : self.fadeIn(ele, strSpeed);
        }, 0);
    },
    slideOut: function(ele, strSpeed){
        var count = 0, u = "px", s = ele.style,
            c = this.config, cs = window.getComputedStyle ? window.getComputedStyle(ele) : ele.currentStyle,
            h = s.height = c.distance = parseFloat(cs["height"]),
            w = s.width = c.distanceW = parseFloat(cs["width"]);

        try{
            var    m$ = this.calculate(strSpeed, h, w);
            setTimeout(function(){
                count++;
                if(count > m$.frames || parseFloat(s.width) < m$.stepw || parseFloat(s.height) < m$.step){
                    s.height = 0;
                    s.width = 0;
                }else{
                    s.height = (parseFloat(s.height) - m$.step) + u;
                    s.width = (parseFloat(s.width) - m$.stepw) + u;
                    setTimeout(arguments.callee, c.interval);
                }
            }, c.interval); 
        }catch(ex)
        {
            console.log("slideOut error, " + ex.message);
        }
        c.show = false;
    },
    slideIn: function(ele, strSpeed){
        var count = 0, u = "px", s = ele.style,
            c = this.config, cs = window.getComputedStyle ? window.getComputedStyle(ele) : ele.currentStyle,
            h = c.distance,
            w = c.distanceW;
        try{
            var    m$ = this.calculate(strSpeed, h, w);
            setTimeout(function(){
                count++;
                if(count > m$.frames || parseFloat(s.width) > c.distanceW || parseFloat(s.height) > c.distance){                            
                    s.height = c.distance + u;
                    s.width = c.distanceW + u;
                }else{
                    s.height = (parseFloat(s.height) + m$.step) + u;
                    s.width = (parseFloat(s.width) + m$.stepw) + u;
                    setTimeout(arguments.callee, c.interval);
                }
            }, c.interval);
        }catch(ex){
            console.log("slideOut error, " + ex.message);
        }
        c.show = true; 
    },
    slideToggle: function(ele, strSpeed){
        this.config.show ? this.slideOut(ele, strSpeed) : this.slideIn(ele, strSpeed);
    }
};

addEvent(btn, "click", bind(animation.fadeToggle, animation, element, "normal"));  //最后调用

  代码还算清晰,主要的难点在于绑定的理解和兼容性的问题。