保持对代码的热爱并保存怀疑态度
建议从js封装运动1,js封装运动2开始一步一步看
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#box1{width: 100px;height: 100px;background: red;position: absolute;left:0;top:0;}
#box2{width: 100px;height: 100px;background: green;position: absolute;left:0;top:130px;}
.line{width: 1px;height: 700px;position:absolute;left: 1000px;background: black;top:0}
</style>
</head>
<body>
<div id="box1"></div>
<div id="box2"></div>
<div class="line"></div>
</body>
<script>
// 运动源
var obox1 = document.getElementById("box1");
var obox2 = document.getElementById("box2");
// 随着时间的变化,减少speed的值
// 不能小于0
obox1.onmouseover = function(){
move(obox1, {left:1000}, function(){
document.body.style.background = "pink";
});
}
obox2.onmouseover = function(){
move(obox2, {left:1000});
}
// 将属性和对应的目标,作为一个对象的键值对传参
function move(ele, data, cb){
//元素,元素的属性和值,结束后要执行的函数
clearInterval(ele.t);
// 将计时器的返回值,保存到每个不同的元素对象身上,方便删除计时器时,删除对应元素的计时器
ele.t = setInterval(() => { //开启计时器 借助了元素的属性值,然后解决点一个未结束的时候点击另一个会停止的问题
var flag = true; //为了后面的判断,怎么清空计时器 ,直接清空的会导致如果你的第一个参数到达了位置后第二个直接停止的问题
for(var i in data){ //遍历对象
var now = i === "opacity" ? gertStyle(ele, i) * 100 : parseInt(gertStyle(ele, i));
//i为对象的键,三目简化,判断是否传入的参数是opacity
//i为对象的键
// parseInt去除"px",因为后面会赋值回去加了px
// 计算步长
var speed = (data[i] - now)/10; //data[i]为对象的值
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 向上取整,因为浏览器执行的时候会忽略小于1像素的(具体解释清看缓冲运动未封装的,有案例测试)
// 向下取整,因为浏览器执行的时候会忽略小于1像素的
ele.style[i] = i === "opacity" ? (now + speed)/100 : now + speed + "px"; //三目简化,传入的是否为opacity
// 所有属性都要目标,才能清除计时器,需要有状态记录,但是每个属性都有一个状态,太浪费空间
// 反向判断,只要有一个属性没到目标,不清除计时器,只需要一个状态,记录是否有属性没到目标
if(now !== data[i]){ //如果现在的位置不等于结束的位置,flag的值改为false
flag = false;
}
}
if(flag){
clearInterval(ele.t); // 如果flag为true表示没有属性没到目标,可以清除计时器了
// 当动画结束后,执行指定功能
cb && cb();
}
}, 30);
}
function gertStyle(ele, attr){ //ele元素 attr为元素的css属性
if(ele.currentStyle){
return ele.currentStyle[attr]; //ie 解决兼容问题
}else{
return getComputedStyle(ele,false)[attr];
}
}
</script>
</html>