简单的运动封装函数
在js的学习当中,我们常常会让元素发生运动,比如说轮播图的渐变效果,元素的左右隐藏显示效果等等,我们每次用到运动的时候重新写一段代码特别的麻烦,我就封装了一段运动函数,每次使用的时候只需要调用一下就可以了
<style>
#box{
width: 100px;
height: 100px;
background-color: yellowgreen;
position: absolute;
left: 0;
top: 0;
}
</style>
<div id="box"></div>
<script>
// 帧数 :
var box_ele = document.getElementById("box");
var timer = null;
// offset获取元素位置,获取一次即可;
var box_left = box_ele.offsetLeft;
// 速度提取出来 ;
var speed = 3;
// 目标点 ;
var target = 555.5;
timer = setInterval(function(){
// 这样的替换实际上就是我们从元素里面取值,赋值变成了对变量进行取值赋值操作;
box_left += speed;
box_ele.style.left = box_left + "px"
// 终止条件;
if( Math.abs( target - box_left ) <= Math.abs(speed) ){
speed = 0;
clearInterval(timer);
}
},30);
</script>
上面这段代码已经可以实现简单的元素从左到右的运动,但是和我们的目标点有一些误差,这是因为速度可能不一定会被我们所定的距离整除,这样就会产生一定的误差,解决办法很简单,我们可以送他一把:
if( Math.abs( target - box_left ) <= Math.abs(speed) ){
// 送他一把 :
box_ele.style.left = target + "px"
clearInterval(timer);
}
当我们设定的目标点和元素当前距离只差小于速度的时候,我们直接让元素的当前位置等于目标点。
当我们将运动行为放置在一个事件之中时,要在开启定时器之前,先关闭定时器,不然用户多次触发事件时,会造成速度越来越快。甚至元素超出了他的限制范围
<div id="box">
<button></button>
</div>
<script>
// 帧数 :
var box_ele = document.getElementById("box");
var btn = document.querySelector("button");
var timer = null;
// offset获取元素位置,获取一次即可;
var box_left = box_ele.offsetLeft;
// 速度提取出来 ;
var speed = 3;
// 目标点 ;
var target = 500;
btn.onclick = function(){
timer = setInterval(function(){
// 这样的替换实际上就是我们从元素里面取值,赋值变成了对变量进行取值赋值操作;
box_left += speed;
box_ele.style.left = box_left + "px"
// 终止条件;
if( Math.abs( target - box_left ) <= Math.abs(speed) ){
// 送他一把 :
box_ele.style.left = target + "px"
clearInterval(timer);
}
},30);
}
</script>
根据上述代码进行总结之后简单的封装:
function animate( target , speed ){
// 根据target 和当前的元素位置判定速度为正数还是负数;
var iNow = box_ele.offsetLeft;
// 判定speed是否存在;
speed = speed === undefined ? 5 : speed;
// 判定speed的正负;
speed = iNow < target ? Math.abs(speed) : -Math.abs(speed);
clearInterval(timer)
timer = setInterval(function(){
if( Math.abs( target - iNow) <= Math.abs(speed) ){
clearInterval(timer);
box_ele.style.left = target + "px";
}else{
// 解决了多次出发事件让元素异常运动的bug;
iNow += speed;
box_ele.style.left = iNow + "px";
}
} , 30)
}
输入的target是目标到达的位置,speed是元素的速度,将这两个参数传递进来之后,可以根据元素现在的位置和目标点的距离求出速度的正负,如果速度大于了目标点和当前位置只差 就直接让元素到达,反之则当前位置 iNow += speed;根据不断的调试完善这个封装我们可以多输入一个参数,比如元素的width或者是height属性,让元素达到变形的效果
#box{
width: 200px;
height: 200px;
background: #ddd;
position: absolute;
}
<div id="box"></div>
function animate( target , attr , speed ){
var iNow = parseInt(getComputedStyle(box_ele)[attr]);
// 判定speed是否存在;
speed = speed === undefined ? 5 : speed;
// 判定speed的正负;
speed = iNow < target ? Math.abs(speed) : -Math.abs(speed);
clearInterval(timer)
timer = setInterval(function(){
if( Math.abs( target - iNow ) <= Math.abs(speed) ){
clearInterval(timer);
box_ele.style[attr] = target + "px";
}else{
iNow += speed;
box_ele.style[attr] = iNow + "px";
}
} , 30)
}
box_ele.addEventListener("mouseover" , function(){
animate( 500 , "width" , 10);
})
根据每次的需求可以不断的完善自己的封装函数,像是元素属性透明度opacity 也是可以进行改变的,只需要在函数内部判断一下改一下数值可以轻易地做到 渐变的效果。
最后附上比较完善的运动函数封装,仅供大家参考。
function animate( ele , attr_options , callback ){
for(var attr in attr_options){
attr_options[attr] = {
// 目标点 : 传入的数据;
target : attr === "opacity" ? attr_options[attr] * 100 : attr_options[attr],
// 元素当前的属性值 ;
iNow : attr === "opacity" ? parseInt( getComputedStyle(ele)[attr] * 100 ) : parseInt( getComputedStyle(ele)[attr])
}
}
// 关闭开启定时器;
clearInterval( ele.timer );
ele.timer = setInterval( function(){
// 1. 获取速度; width : height :
for(var attr in attr_options){
// attr : width | height;
var item = attr_options[attr];
// console.log(item , attr);
var target = item.target;
var iNow = item.iNow;
// 运动所必须的值我们都有了;
// 计算速度;
var speed = (target - iNow) / 10;
// 速度取整;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 终止条件 :
if( Math.abs( target - iNow) <= Math.abs(speed) ){
// 终止定时器 ;
// 送他一把;
// clearInterval( ele.timer );
// ele.style[attr] = target + "px";
// 终止条件不可靠,因为目标的不一致会让运动次数执行不同,有可能提前关闭定时器;
ele.style[attr] = attr === "opacity" ? target / 100 : target + "px";
// 一条运动完成删除对象里面的数据;
delete attr_options[attr];
// 如果对象里面没有属性了,那么我们关闭定时器就可以了;
for(var num in attr_options){
// 如果attr_options里面有属性,那么此时我就不应该终止定时器;
return false;
}
clearInterval(ele.timer);
typeof callback === "function" ? callback() : "";
}else{
// 元素运动;
// 因为 iNow 是一个临时变量,所以不能再去操作iNow , 要去操作iNow 的数据源;
// 多花点经历理解这段代码;
attr_options[attr].iNow += speed;
ele.style[attr] = attr === "opacity" ? attr_options[attr].iNow / 100 : attr_options[attr].iNow + "px";
}
}
} , 30)
}