JS 同步动画
先修缮一下百度分享栏的自动居住问题。
之前是每次刷新会自动居中,这里我们要改为当用户滑动时也会自动居中。
addEvent(window,'scroll',function(){
$('#share').css('top',getScroll().height + (getInner().height - parseInt(getStyle($('#share').first(),'height')))/2 + 'px');
});
//跨浏览器获取scroll大小
function getScroll() {
return {
width : document.body.scrollLeft != 0 ? document.body.scrollLeft : document.documentElement.scrollLeft,
height : document.body.scrollTop != 0 ? document.body.scrollTop : document.documentElement.scrollTop
}
};
分享栏之前就以及算好了可视高度自动居中的高度,那么只要加上被滚动后距离就可以达到居中的效果,在window下的scroll事件中每次触发都是加上对应的scroll高度,以此达到滚动自动居中。
改为动画效果:
//设置百度分享菜单自动居中
addEvent(window, 'scroll', function() {
$('#share').animation({
'attr': 'y',
'end': getScroll().height + (getInner().height - parseInt(getStyle($('#share').first(), 'height'))) / 2
});
});
同步动画:
同步动画需要新传入一个键值对参数,这个键值对里面保存着需要同时运行的动画参数。
animation({
mul {
'x' : 300,
'y' : 300
}
})
这个mul就表示需要同步运行的动画有x轴移动到300,y轴移动到300。
为此animation封装库中需要新建一个变量用于保存这个mul参数,而且在判断的时候,end的值要等于mul中的300。
同步运行需要在同一个timer超时调用中,为此只能通过for语句循环这个mul,里面有几个参数,就循环调用几次,在同一个timer中,相同的time时间内。
于是:
调用函数
//设置动画
$('#pox').click(function() {
$('#box').animation({
'attr': 'x',
'end': -100,
'step': 7,
'type': 1,
'mul': {
'o': 30,
'h': 500
}
})
});
同时让透明度为30,高度500px。
封装库
//设置动画
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;
var mul = obj['mul'];
if (add != undefined && end == undefined) {
end = add + start;
} else if (add == undefined && end == undefined && mul == 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';
}
if (mul == undefined) {
mul = {};
mul[attr] = end;
}
clearInterval(element.timer);
element.timer = setInterval(function() {
for (var i in mul) {
attr = i == 'x' ? 'left' : i == 'y' ? 'top' :
i == 'w' ? 'width' : i == 'h' ? 'height' :
i == 'o' ? 'opacity' : i != undefined ? i : 'left';
end = mul[i];
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);
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();
}
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;
}
首先var mul = obj[‘mul’];保存传入的mul参数。
然后在if判断是否传入值得时候加上 mul != undefined 的条件。
在超时调用timer中,通过for... in.. 语句枚举出mul中的键值对的名称,然后判断i是什么值,再将对应的值附给attr。
end的值就直接mul[i]即可获得。
然后将step步进和修改css的代码当如这个for...in..语句中,这样每次for循环的时候就会运行一次对应的修改css代码,加上前面我们已经将attr和end的值改为mul传入的值,最后因为是在同一个timer中,同一段时间,于是达到了同步运行动画的效果。
但是这样我们导致单独设置动画,不用mul就是失效,因为我们在timer中重置了attr和end的值,所以在创建超时调用之前还要做个判断。
if (mul == undefined) {
mul = {};
mul[attr] = end;
}
如果mul没有值,说明就是单次效果,那么我们将mul重新赋值为一个对象,然后通过键值对的方式设置参数即可。
但是这样设置的attr实际上已经是完整的名称了,如width,height等等,所以在超时调用中i在判断的时候加上,如果前面的都不是,而且i也不是undefined,那么就等于这个i就可以了,那么这个i就是完整的名称。
那么之前的var attr = xxx 也可以加上这句话,这样我们既可以通过缩写设置参数,也可以通过写完整名称来设置。
var attr = obj['attr'] == 'x' ? 'left' : obj['attr'] == 'y' ? 'top' :
obj['attr'] == 'w' ? 'width' : obj['attr'] == 'h' ? 'height' :
obj['attr'] == 'o' ? 'opacity' : obj['attr'] != undefined ? obj['attr'] : 'left';
以上动画就完成了,下面我们综合测试一下:
调用函数:
//设置动画
$('#pox').click(function() {
$('#box').animation({
'attr': 'x',
'end': -100,
'step': 7,
'type': 1,
'mul': {
'o': 30,
'h': 500
},
'fn': function() {
$('#box').animation({
'attr': 'x',
'end': 500
})
}
})
});
效果图:
这里我们可以看到同步和队列都可以运行,而且互不影响,但是单个设置会被同步设置覆盖,因为我们之前做了判断,if (mul == undefined) {}。
以上完成。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据