function animate(options, dom, callback) {
// 之前的参数是 attr 和 target ,但是没办法满足多个属性同时传入的需求;
// - 因此我们把attr和target参数优化成了 options 对象参数 , 这样方便多条数据传入;
// 1. 格式化options对象,把原本只有目标点的数据变成 :
// { 属性 : { 目标点信息 , 当前位置信息 } }
for (var attr in options) {
// 计算 当前的属性值;
if (attr === "opacity") {
// 如果是透明度运动,需要让属性值放大100倍
var attr_now = parseInt(getComputedStyle(dom)[attr] * 100);
} else {
var attr_now = parseInt(getComputedStyle(dom)[attr]);
}
options[attr] = {
// 如果是透明度运动我们需要让目标点也扩大100倍;
target: attr == "opacity" ? options[attr] * 100 : options[attr],
attr_now: attr_now
};
}
// 运动定时器 :
// 清空定时器
clearInterval(dom.t)
// 定时器设置
dom.t = setInterval(function () {
// 如果我们不想开启多个定时器来操作运动属性,那么我们可以在一个定时器里面使用for循环来完成多次属性赋值;
for (var attr in options) {
// 先提取运动关键值 :
var target = options[attr].target;
var attr_now = options[attr].attr_now;
// 下半部分代码没有任何改变;
var speed = (target - attr_now) / 10;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 关停定时器;
// - 因为现在很多属性公用一个定时器,所以我们需要对对象进行检查, 看看是否还有未完成运动的属性,如果有就不关闭定时器,如果没有再去关闭定时器;
if (target === attr_now) {
// 规则 : 如果当前的属性完成运动了,我们就在options之中删除掉这个属性 ;
delete options[attr];
// 对象之中是没有判定剩余数量的API的,但是数组有;
// Object.keys 会返回对象之中所有的key,并且这个key值是以数组形式返回的;
var keys_arr = Object.keys(options)
// 如果keys_arr里面key的数量为0,那么我们就关闭定时器,否则就不用关闭定时器;
if (keys_arr.length === 0) {
clearInterval(dom.t);
// 在动画执行结束之后调用callback函数;
// - callback是可选参数,所以我们要判定这个函数是否存在再去进行套调用;
typeof callback === "function" ? callback() : "";
}
} else {
// 更改数据的时候应该更改 options 里面的数据,所有的数据来源都来自于options为了让下一次计算在本次计算的基础上进行所以我们更改了 options里面的数据;
attr_now += speed;
options[attr].attr_now = attr_now;
// 操作的元素可能发生改变么 ?
// 可能 ;
// 判断是不是opacity 如果是不加 px 单位并且/100;
if (attr === "opacity") {
dom.style[attr] = attr_now / 100;
} else {
dom.style[attr] = attr_now + "px";
}
}
}
}, 30)
}
JS简单的运动封装
于 2022-05-08 16:00:06 首次发布