预览图:

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

HTML部分:

xml
复制代码
<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部分:

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部分:

封装库

javascript
复制代码
//设置遮罩层 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; }

调用部分

javascript
复制代码
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的作用域,并不是你点击的对象。

javascript
复制代码
$('#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,此时这个变量就是点击的元素了

javascript
复制代码
$('#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的方法,不就可以达到运行完一个动画再运行下一个动画的效果了 。

于是

javascript
复制代码
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发生了变化。

javascript
复制代码
//设置动画 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 标签: 增强弹窗动画列队

评论

暂无评论数据

暂无评论数据

目录