<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/* 给各个标签一个简单样式 */
div{
width: 100px;
height: 100px;
background: pink;
position: fixed;
top: 50px;
left: calc(50% - 50px);
}
h1{
width: 100px;
height: 100px;
background: orange;
position: fixed;
top: 300px;
left: calc(50% - 50px);
}
p{
width: 100px;
height: 100px;
background: green;
position: fixed;
top: 580px;
left: calc(50% - 50px);
}
</style>
</head>
<body>
<button>div的按钮</button>
<button>h1的按钮</button>
<button>P的按钮</button>
<div></div>
<h1></h1>
<p></p>
<script>
// 获取各个标签
let oBtn = document.querySelectorAll('button');
let oDiv = document.querySelector('div');
let oH1 = document.querySelector('h1');
let oP = document.querySelector('p');
// 多属性运动函数封装完毕后 对button绑定 click 事件
// 并调用封装好的多属性运动函数
// 根据个人需求写入具体的参数值
oBtn[0].addEventListener('click',function(){
move(oDiv,{width:500, height:200,left:60},function(){oDiv.style.background = 'red'})
})
oBtn[1].addEventListener('click',function(){
move(oH1,{height:300,width:400,top:50},function(){oH1.style.background = 'black'})
})
oBtn[2].addEventListener('click',function(){
move(oP,{height:200,width:500,right:80},function(){oP.style.background = 'blue'})
})
// move 多属性运动函数
// @param 参数1 element 要运动的标签对象
// @param 参数2 typeObj 要运动的属性 和最终属性值
// @param 参数3 comeBack 运动执行的回调函数 默认返回值为空函数
function move(element , typeObj, comeBack = function(){}){
// 定义变量num 方便用于记录定时器目前存在的个数
var num = 0;
// 对typeObj执行遍历操作
// 获取每一个属性type
for(let type in typeObj){
// 获取初始值 如果初始属性为 opacity 则需要做兼容出理
let startNum = type === 'opacity' ? window.getComputedStyle(element)[type]*100 : parseInt(window.getComputedStyle(element)[type]);
// 获取最终值 同样需要对 opacity 情况做兼容处理
let endNum = type === 'opacity' ? typeObj[type]*100 : typeObj[type];
// 给 num++ 记录产生定时器的个数
num ++ ;
// 设定计时器 表变量time 记录定时器的序号 时间间隔为30毫秒
let time = setInterval(function(){
// 计算步长 每一次步长即为 对应标签属性值的增减 也即是标签对象每次运动的距离
let step = (endNum - startNum)/20;
// 因为步长的产生 并不一定就是整数值 其可能为小数参与运算的值
// 小数参与运算 会产生精度丢失的问题 导致最终函数的执行也会产生问题
// 故需要做步长的向上或向下取整的操作 向上取整为正数运算 向下取整为负数时操作
// 从而避免精度丢失的问题 为函数造成的一些列问题
step = step > 0 ? Math.ceil(step) : Math.floor(step);
startNum += step ;
// 将程序算得的最终运动值 符值给要运动标签的属性的值
element.style[type] = type === 'opacity' ? startNum/100 : startNum + 'px';
// 进行条件判断 条件满足 即为移动到最终位置 则需要清楚计时器
if(startNum === endNum){
clearInterval(time);
// 计时器被清楚 也意味着计时器个数减少 故需要num--
num--;
// 进行条件判断 条件满足 即为所有计时器被器出完毕
// 也即是所有属性运动完毕 则回调函数
if(num === 0){
comeBack();
}
}
},30)
}
}
// @码上成功~
</script>
</body>
</html>