js动画函数封装–单物体运动
对一个div进行宽高属性的变化,对透明度属性进行变化。
*{margin: 0; padding: 0;} /\*样式\*/ <div id="parent"><div id="son">分享</div> </div> /*结构*/ #parent {position: relative; width: 200px; height: 200px; background-color: #f00; margin-left: -200px;} #son {position: absolute; width: 30px; height: 50px; background-color: green; top: 50%; right:-30px; transform: translateY(-50%); text-align: center; } window.onload=function(){ //首先加载函数在dom加载后 var parent=document.getElementById("parent"); //获得父级dom元素 parent.onmousemove=function(){ //当鼠标在父级元素上移动时,触发事件 move(10,0); //move 函数对进行处理 } parent.onmouseout=function(){ //当鼠标离开父级元素时,触发事件 move(-10,-200); }} var timer=null; function move(speed,target){ clearInterval(timer); //每次在进入move之前都清除定时器 var parent=document.getElementById("parent"); timer=setInterval(function(){ //设置定时器 if(parent.offsetLeft==target){ //假如满足条件,清除定时器 clearInterval(timer); }else{ //否则进行进一步处理 parent.style.marginLeft=parent.offsetLeft+speed+"px"; } },30); } /*js代码*/
这里可能像我这样的新手对
parent.offsetLeft
、marginLeft
对这些属性比较陌生,具体可以参考这篇文章 offsetLeft,有图有真相。透明度属性的处理
#opcity {width: 200px; height: 200px; background-color: #f00; filter: alpha(opacity=30); /*兼容IE9 以下*/opacity: 0.3; } /*样式*/ <div id="opcity"></div> /*结构*/ window.onload=function(){ var opcity=document.getElementById("opcity"); opcity.onmousemove=function(){ move(100); } opcity.onmouseout=function(){ move(30); } } var timer=null; var op=30; function move(arg){ clearInterval(timer); var opcity=document.getElementById("opcity"); timer=setInterval(function(){ var speed=0; if(op<arg){ speed=10; }else { speed=-10; } if(op==arg){ clearInterval(timer); }else { op+=speed; opcity.style.filter="alpha(opacity="+op+")"; /*兼容IE的写法*/ opcity.style.opacity=op/100; } },30); } /*js代码*/
这里的代码基本和上面基本上是一样的,主要是要对
opacity
进行处理,这里在后面还有一种处理办法,由于opacity
传进来是0.3这样的小数,可以先用parseFloat()
对opacity进行处理,然后在乘以100使其变成一个整数,然后在进行后面的处理。
js动画函数封装–多物体运动
div {width: 400px; height: 200px; background-color: yellow; border: 2px solid #666; margin-bottom: 20px;} /*样式*/
<div id="test"></div>
<div id="test1"></div> /*结构*/
window.onload=function(){
var test= document.getElementById("test");
var test1= document.getElementById("test1");
test.timer=null;
test1.timer=null;
test.onmouseover=function(){
move(this,'width',200);
}
test.onmouseout=function(){
move(this,'width',400);
}
test1.onmouseover=function(){
move(this,'height',400);
}
test1.onmouseout=function(){
move(this,'height',200);
}
}
function move(obj,attr,target){
clearInterval(obj.timer);
obj.timer=setInterval(function(){
var pa= parseInt(getStyle(obj,attr));
var speed=(target-pa)/8;
speed=(speed>0)?Math.ceil(speed):Math.floor(speed);
obj.style[attr]=pa+speed+"px";
},30);
}
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr]; /*IE 方法*/
}else {
return getComputedStyle(obj,false)[attr]; /*chrome ,ff*/
}
} /*js代码*/
这里新封装一个函数,
getStyle()
用来获取DOM元素样式,对currentStyle
和getComputedStyle
有疑问的可以参考一下张鑫旭大神的这篇文章currentStyle getComputedStyle,到这一步开始有进一步对函数的封装,记得开始的时候单物体运动的时候,只有一个属性,只需要传一个参数,对opacity
的处理大致也差不多,只是要多一点转化,对于多物体运动,属性的值是在变化的,而且test test1
一个改变宽,一个改变高,所以可以对函数可以进一步封装,这里对于opacity
处理是有问题的,需要在函数内部进行判断,选择不同的分支。这里还要注意的是定时器不能共用,要单独设置自己的定时器。
js动画函数封装–缓冲运动
基本结构和上面单物体结构相同
<script type="text/javascript">
window.onload=function(){
var parent=document.getElementById("parent");
parent.onmousemove=function(){
move(0);
}
parent.onmouseout=function(){
move(-200);
}
}
var timer=null;
function move(target){
clearInterval(timer);
var parent=document.getElementById("parent");
timer=setInterval(function(){
var speed=(target-parent.offsetLeft)/20; //缓冲运动
speed=(speed>0)?Math.ceil(speed):Math.floor(speed);
if(parent.offsetLeft==target){
clearInterval(timer);
}else {
parent.style.marginLeft=parent.offsetLeft+speed+"px";
}
},30);
}
再单物体运动中,我们每次都是加上一个恒定大小的值,其实就是一个匀速运动,为了做一个缓冲运动,我们首先联想到火车进站的时候,一般都是先加速,在减速,最后慢慢加速离开,缓冲运动就类似这种情况parent.style.marginLeft=parent.offsetLeft+speed+"px";
,通过传过来的目标参数与实际样式的值进行一个做差处理,然后除以一个数字,刚开始是极值,speed
的值变化较大,到后面随着两值比较接近,speed
越来越趋近与0,为了最后能达到目标值,要让speed
变为1,再慢慢达到目标值,所以会使用Math.floor()和 Math.ceil()
向上取整和向下取整函数,假如speed>0,则像上取整,假如speed<0,则向下取整,取值+1和-1.
js动画函数封装–单物体的多属性同时运动
<div id="test"></div>
div {width: 400px; height: 200px; background-color: yellow; border: 2px solid #666; margin-bottom: 20px; filter: alpha(opacity=30); /**兼容IE 6*/ opacity: 0.3;}
window.onload=function(){
var test= document.getElementById("test");
test.timer=null;
test.alpha=30;
test.onmouseover=function(){
move(this,{"width": 600, "height": 400, "opacity": 100});
}
test.onmouseout=function(){
move(this,{"width": 400, "height": 200, "opacity": 30})
}
}
var flag=true;
function move(obj,json,fn){
clearInterval(obj.timer);
obj.timer=setInterval(function(){
for(attr in json){
if(attr=="opacity"){
var pa= parseFloat(getStyle(obj,attr))*100;
}else{
var pa= parseInt(getStyle(obj,attr));
}
var speed=(json[attr]-pa)/8;
speed=(speed>0)?Math.ceil(speed):Math.floor(speed);
if(json[attr]!=pa){
flag=false;
}
if(attr=="opacity"){
obj.alpha+=speed;
obj.style.filter="alpha(opacity="+obj.alpha+")";
obj.style[attr]=(obj.alpha)/100;
}else{
obj.style[attr]=pa+speed+"px";
}
}
if(flag){
clearInterval(obj.timer);
if(fn){
fn();
}
}
},30);
}
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];
}else {
return getComputedStyle(obj,false)[attr];
}
}
为了实现单物体的多属性同时运动,使用到json
格式传参,然后对json
里的每一个属性,在定时器里用for in
循环进行遍历,用getStyle()
对获取属性进行处理。
js动画函数封装–单物体的链式运动
.clearfix:after {content: "."; display: block; clear: both; visibility: hidden; height: 0;}
*{margin: 0; padding: 0;}
#content {width: 660px; height: 210px; border: 2px solid #ccc; margin :20px auto; font-size: 0;}
#content a {position: relative; display: inline-block; width: 120px; height: 80px; text-align: center; font: bold 14px/1 Arial; color: #f3f3f3; text-decoration: none; border: 2px solid orange; margin: 10px 20px;}
#content a:hover {color: orange;}
#content a p {position: relative; margin-top: 10px; bottom: -45px;}
#content a i {position: absolute; top: 5px; left: 40px; display: inline-block; filter: alpha(opacity=100); opacity: 1;}
<div id="content">
<a href="#">
<i><img src="images/001.jpg" alt=""></i>
<p>便民</p>
</a>
<a href="#">
<i><img src="images/002.jpg" alt=""></i>
<p>充值</p>
</a>
<a href="#">
<i><img src="images/003.jpg" alt=""></i>
<p>旅行</p>
</a>
<a href="#">
<i><img src="images/004.jpg" alt=""></i>
<p>缴费</p>
</a>
<a href="#">
<i><img src="images/005.jpg" alt=""></i>
<p>电影</p>
</a>
<a href="#">
<i><img src="images/006.jpg" alt=""></i>
<p>音乐</p>
</a>
<a href="#">
<i><img src="images/007.jpg" alt=""></i>
<p>教育</p>
</a>
<a href="#">
<i><img src="images/008.jpg" alt=""></i>
<p>能源</p>
</a>
</div>
window.onload=function(){
var content= document.getElementById("content");
var links= content.getElementsByTagName("a");
for (var i = 0; i < links.length; i++) {
links[i].onmouseenter=function(){
var inode=this.getElementsByTagName("i")[0];
inode.timer=null;
inode.alpha=30;
move(inode,{marginTop:-40,opacity: 0},function(){
inode.style.marginTop=20+"px";
move(inode,{marginTop:5,opacity: 100});
});
}
}
}
//获取样式
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];
}else {
return getComputedStyle(obj,false)[attr];
}
}
//move 函数
function move(obj,json,fn){
clearInterval(obj.timer);
obj.timer=setInterval(function(){
var flag=true;
for(attr in json){
if(attr=="opacity"){
var pa= parseFloat(getStyle(obj,attr))*100;
}else{
var pa= parseInt(getStyle(obj,attr));
}
var speed=(json[attr]-pa)/8;
speed=(speed>0)?Math.ceil(speed):Math.floor(speed);
if(json[attr]!=pa){
flag=false;
}
if(attr=="opacity"){
obj.alpha+=speed;
obj.style.filter="alpha(opacity="+obj.alpha+")";
obj.style[attr]=(obj.alpha)/100;
}else{
obj.style[attr]=pa+speed+"px";
}
}
if(flag){
clearInterval(obj.timer);
if(fn){
fn();
}
}
},30);
}function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];
}else {
return getComputedStyle(obj,false)[attr];
}
}
对于链式运动,首先move()
函数本身多传入一个函数参数,在move()
函数在在处理好函数体的变化后,假如函数参数有值传入,则要执行后面的函数体,假如后面的参数还有函数参数,则可以继续执行下去,这样就形成了一条执行链。我上面这个列子还有一些问题,当你鼠标移动过快,会产生闪烁。具体学习视频参考慕课网JS动画效果.