预览图:

之前在登录框弹窗时我们做了一个遮罩层,当时的遮罩层是通过js创建了,但是如果要加上动画效果,那么你创建的话就十分不方便,所以这里直接在html上建了一个div元素,然后通过js设置css。

HTML部分:

<div class="">
    <div id="login_masked"></div> //这里创建一个div元素用于遮罩层
    <div id="login">
        <i class="login_off"><span class="off">+</span></i>
        <h2 id="login_title">网站登录</h2>
        <form action="" id="login_form">
            <div class="user">账 号:<input type="text" name="user" class="text" /></div>
            <div class="pass">密 码:<input type="password" name="pass" class="text" /></div>
            <div class="buttom"><input type="button" name="submit" value="登录" class="submit" /></div>
            <div class="other">注册新用户 | 忘记密码?</div>
        </form>
    </div>
</div>

CSS部分:

#login_masked {
    position: absolute;
    top: 0;
    left: 0;
    display: none;
    background-color: #000;
    opacity: 0;
    filter: alpha(opacity=0);
}

遮罩层自然是要控制大小的,并且不会占据空间,这里使用absolute,但是绝对定位他有一个位置跟随性,如果你没有设置他的top和left的位置,那么默认是在原来的位置上的,所以这里top:0;left:0;做一个位置重置。

默认遮罩层是不显示的,这里就设置display: none; 透明度为0;

当用户点击后遮罩层弹出,宽度和高度为可视宽高,display:block;透明度为0.3

JS部分:

封装库

//设置遮罩层
Base.prototype.Masked = function() {
    for(var i = 0;i<this.arr.length;i++)  {
        this.arr[i].style.width = getInner().width + 'px';
        this.arr[i].style.height = getInner().height + 'px';
        addEvent(window,'scroll',scrollTop);
    }
    return this;
}


//删除遮罩层
Base.prototype.removeMasked = function() {
    for(var i = 0;i<this.arr.length;i++)  {
        this.arr[i].style.display = 'none'
        removeEvent(window,'scroll',scrollTop);
    }
    return this;
}

调用部分

var login = $('#login');
var masked = $('#login_masked');

$('#header .nav-login').hover(function(){
    $(this).css('background-color','rgba(0,0,0,.3)');
    },function() {
        $(this).css('background-color','rgba(0,0,0,0)');
    });
    
$('#header .nav-login').click(function(){
    login.css('clip','auto').css('opacity','1').center().resize(function(){
        if(login.css('opacity') == '1'){
            masked.Masked();
        };
    });
    masked.css('display','block').Masked().animation({
        'attr' : 'o',
        'end' : 30,
        'step' : 7,
    });
    $('html').css('overflow','hidden');
});

$('#login .login_off').click(function(){
    login.css('clip','rect(0 0 0 0)').css('opacity','0');
    masked.animation({
        'attr' : 'o',
        'end' : 0,
        'step' : 7,
        'fn' : function(){
            masked.removeMasked();
        }
    });
    $('html').css('overflow','auto');
});

调用的时候,我们使用了新的方法,就是动画队列,当一个动画完成后触发另一个动画。

其原理就是在传入的obj对象中最后写了一个fn的属性,然后他赋予一个function,这个function里面写好下一个需要触发的动画,这里我们在login_off元素,关闭按钮上使用了这个方法,当用户点击关闭按钮后,先是遮罩层从不透明转为透明,然后再触发删除遮罩层效果。

如果说你想要使用this对象,那么直接在fn的function中写是无效的,此时的这个this指向的是fn的作用域,并不是你点击的对象。

$('#login .login_off').click(function(){
    login.css('clip','rect(0 0 0 0)').css('opacity','0');
    masked.animation({
        'attr' : 'o',
        'end' : 0,
        'step' : 7,
        'fn' : function(){
            alert(this);  // this不是指向login_off元素,而是fn  
        }
    });
    $('html').css('overflow','auto');
});

让this指向login_off也很简单,在click的function中创建一个变量,并等于this,此时这个变量就是点击的元素了

$('#login .login_off').click(function(){
    var _this = this;
    login.css('clip','rect(0 0 0 0)').css('opacity','0');
    masked.animation({
        'attr' : 'o',
        'end' : 0,
        'step' : 7,
        'fn' : function(){
            alert(_this);  // _this指向login_off
        }
    });
    $('html').css('overflow','auto');
});

我们使用的队列方法要在动画的封装库中修改一下。

我们在超时调用timer的里面if判断是否已经达到要求,然后运行对应的 setOpacity();和 setAttr();方法,这两个方法运行说明已经达到要求了,那么这个动画已经结束,那么我们只需要在这两个函数中最后面添加运行obj传入的fn的方法,不就可以达到运行完一个动画再运行下一个动画的效果了 。

于是

 function setAttr() {
     element.style[attr] = end + 'px';
     clearInterval(element.timer);
     if (obj.fn != undefined) obj.fn();
 }

 function setOpacity() {
     element.style.opacity = parseInt(end) / 100;
     element.style.filter = 'alpha(opacity=' + parseInt(end) + ')';
     clearInterval(element.timer);
     if (obj.fn != undefined) obj.fn();
 }

防止错误做一个if判断,fn存在就运行fn的方法。

以上设置好后,当我们点击登录时,遮罩层会有动画效果,点击关闭按钮,遮罩层会先慢慢透明,最后再被display:none;

即便如此,但是还有一个bug需要调整,就是我们不管调用动画的元素有几个,他们都是共用一个timer超时调用,也就是window.timer;这样就会产生一个问题,当你快速触发多个动画效果的元素时,元素动画没有完成就被清理掉了timer然后又触发下一个元素动画,这样就会导致前面的元素就好像卡住了一样,但是你单个调用时便不会有这个问题。

修复共用一个timer

下面我们来整理下思绪。

首先就是触发的事件,我们的事件都是在元素上触发的,以hover()方法中的mouseover和mouseout事件来讲,当鼠标移入这个元素时,触发mouseover事件,这个事件调用animation动画,动画里面创建window.timer超时调用。当你在这个元素里面不断移动时,触发的元素永远是同一个。

那么我们创建window.timer的原因是因为事件会重复调用animation动画,然后不断创建timer超时调用,所以只能创建一个可以被找到的timer,也就是window.timer,然后在第二次调用时清理掉之前的。

既然是要一个可以被找到的timer,而每次触发的元素都是同一个,那直接创建一个这个元素的timer。

于是

element.timer 即可,这个超时调用既可以在重复的时候被找到,在不同的元素触发的时候也不会清理到之前的,因为element发生了变化。

//设置动画
Base.prototype.animation = function(obj) {
    for (var i = 0; i < this.arr.length; i++) {
        var element = this.arr[i];
        var attr = obj['attr'] == 'x' ? 'left' : obj['attr'] == 'y' ? 'top' :
            obj['attr'] == 'w' ? 'width' : obj['attr'] == 'h' ? 'height' :
            obj['attr'] == 'o' ? 'opacity' : 'left';
        var start = obj['start'] != undefined ? obj['start'] :
            attr == 'opacity' ? getOpacity() :
            parseInt(getStyle(element, attr));
        var step = obj['step'] != undefined ? obj['step'] : 20;
        var time = obj['time'] != undefined ? obj['time'] : 30;
        var add = obj['add'];
        var end = obj['end'];
        var type = obj['type'] == 0 ? 'constant' : obj['type'] == 1 ? 'buffer' : 'buffer';
        var speed = obj['speed'] != undefined ? obj['speed'] : 6;

        if (add != undefined && end == undefined) {
            end = add + start;
        } else if (add == undefined && end == undefined) {
            throw new Error('alter增量或target目标量必须传一个!');
        }
        if (start > end) step = -step;

        if (attr == 'opacity') {
            element.style.opacity = start / 100;
            element.style.filter = 'alpha(opacity=' + start + ')';
        } else {
            element.style[attr] = start + 'px';
        }
        clearInterval(element.timer); //创建element下的timer
        element.timer = setInterval(function() {
            if (type == 'buffer') {
                step = attr == 'opacity' ? (end - getOpacity()) / speed :
                    (end - parseInt(getStyle(element, attr))) / speed;
                step = (step > 0) ? Math.ceil(step) : Math.floor(step);
            }
            //document.getElementById('dox').innerHTML += getStyle(element, attr) + 'px' + '<br/>';
            if (attr == 'opacity') {
                if (step == 0) {
                    setOpacity();
                } else if (step > 0 && Math.abs(getOpacity() - end) <= step) {
                    setOpacity();
                } else if (step < 0 && (getOpacity() - end) <= Math.abs(step)) {
                    setOpacity();
                } else {
                    var temp = getOpacity();
                    element.style.opacity = (temp + step) / 100;
                    element.style.filter = 'alpha(opacity=' + (temp + step) + ')'
                }
            } else {
                if (step == 0) {
                    setAttr();
                } else if (step > 0 && Math.abs(parseInt(getStyle(element, attr)) - end) <= step) {
                    setAttr();
                } else if (step < 0 && (parseInt(getStyle(element, attr)) - end) <= Math.abs(step)) {
                    setAttr();
                } else {
                    element.style[attr] = parseInt(getStyle(element, attr)) + step + 'px';
                }
            };
        }, time);

        function setAttr() {
            element.style[attr] = end + 'px';
            clearInterval(element.timer); //达成目标清理对应的timer
            if (obj.fn != undefined) obj.fn();
        }

        function setOpacity() {
            element.style.opacity = parseInt(end) / 100;
            element.style.filter = 'alpha(opacity=' + parseInt(end) + ')';
            clearInterval(element.timer); //达成目标清理对应的timer
            if (obj.fn != undefined) obj.fn();
        }

        function getOpacity() {
            if (system.ie <= 8) {
                var op = getStyle(element, 'filter');
                var s = [];
                if (op.match(/opacity=([\d]+)/)) {
                    s = op.match(/\=([\d]+)/);
                } else {
                    throw new Error('ie8一下没有获取到filter中的opacity值');
                }
                return parseInt(s[1]);
            } else {
                return parseFloat(getStyle(element, 'opacity')) * 100;
            }
        }
    }
    return this;
}

以上,修缮完成。

分类: JavaScript 标签: 增强弹窗动画列队

评论

暂无评论数据

暂无评论数据

目录