<body>
<button id="begin">开始运动button>
<button id="stop">停止运动button>
<div>div>
<script>
let begin = document.querySelector('#begin');
let cease = document.querySelector('#stop');
let div = document.querySelector('div');
/* let target = 600;
let direction = "top" */
let timer;
begin.onclick = function () {
animate(div, {left:0,top:0});
}
function animate(el, obj) {
timer = setInterval(() => {
let count =0;
for (key in obj) {
let target = obj[key];
let current = parseInt(getComputedStyle(el)[key]);
console.log(obj.current);
let speed = (target - current) / 10;
console.log(target,current);
if (speed < 0) {
speed = Math.floor(speed);
} else {
speed = Math.ceil(speed);
}
el.style[key] = current + speed + "px";
//当前的值等于目标值清除定时器
if (speed == 0) {
clearInterval(timer);
}
}
}, 200);
}
cease.onclick = function () {
clearInterval(timer);
}
script>

原来位置left: 50px; top: 400px;
js目标移动到left:0,top:0
执行完left后定时器就停止了,top还没走到0
基于Monster 组和GPT的调写:
代码中有一个问题是在 setInterval 中使用了一个 for...in 循环遍历对象的属性,而在循环中使用了一个变量 key,但在 console.log(obj.current) 中又将它写成了 obj.current,这样会导致输出 undefined。正确的写法应该是 console.log(current)。
另一个问题是,当多个属性的动画同时进行时,只要其中一个属性的动画到达目标值就会清除定时器,这会导致其他属性的动画还没有完成就被中止了。
为了解决这个问题,要在每次循环中记录当前所有属性的动画是否都已完成,只有所有属性的动画都完成了,才清除定时器。
以下是修改后的代码
<body>
<button id="begin">开始运动</button>
<button id="stop">停止运动</button>
<div style="position: absolute; left: 50px; top: 400px;">Hello, world!</div>
<script>
let begin = document.querySelector('#begin');
let cease = document.querySelector('#stop');
let div = document.querySelector('div');
let timer;
begin.onclick = function () {
animate(div, {left: 0, top: 0});
}
function animate(el, obj) {
clearInterval(timer);
timer = setInterval(() => {
let allFinished = true;
for (let key in obj) {
let target = obj[key];
let current = parseInt(getComputedStyle(el)[key]);
let speed = (target - current) / 10;
if (speed < 0) {
speed = Math.floor(speed);
} else {
speed = Math.ceil(speed);
}
el.style[key] = current + speed + "px";
if (current !== target) {
allFinished = false;
}
}
if (allFinished) {
clearInterval(timer);
}
}, 200);
}
cease.onclick = function () {
clearInterval(timer);
}
</script>
</body>
回答引用ChatGPT:在你的代码中,如果一个属性已经达到目标值,则应该将该属性从对象中删除,以便定时器可以在所有属性都到达目标值时停止。你可以通过添加一个变量 finishCount 来跟踪已完成动画的属性数量,并在计算 speed 和更新属性值之前检查 finishCount 的值。
下面是更新后的代码:
<body>
<button id="begin">开始运动</button>
<button id="stop">停止运动</button>
<div style="position: absolute; left: 50px; top: 400px; width: 100px; height: 100px; background-color: red;"></div>
<script>
let begin = document.querySelector('#begin');
let cease = document.querySelector('#stop');
let div = document.querySelector('div');
let timer;
begin.onclick = function () {
animate(div, {left: 0, top: 0});
}
function animate(el, obj) {
let finishCount = 0;
timer = setInterval(() => {
for (let key in obj) {
let target = obj[key];
let current = parseInt(getComputedStyle(el)[key]);
let speed = (target - current) / 10;
if (speed < 0) {
speed = Math.floor(speed);
} else {
speed = Math.ceil(speed);
}
let newValue = current + speed;
if (newValue === target) {
finishCount++;
delete obj[key];
}
el.style[key] = newValue + "px";
}
if (finishCount === Object.keys(obj).length) {
clearInterval(timer);
}
}, 200);
}
cease.onclick = function () {
clearInterval(timer);
}
</script>
</body>
在这个修改后的代码中,我们首先在 animate 函数内部添加了一个 finishCount 变量,它的初始值为 0。然后,我们遍历 obj 中的每个属性,计算它们的 speed,更新属性值并检查是否达到目标值。如果达到目标值,则我们增加 finishCount 的值,并使用 delete 运算符将该属性从 obj 中删除。最后,我们检查 finishCount 的值是否等于 obj 中剩余属性的数量。如果是,则说明所有属性都已到达目标值,我们清除定时器。
该回答引用ChatGPT
function animate(el, obj) {
timer = setInterval(() => {
let count = 0;
for (key in obj) {
let target = obj[key];
let current = parseInt(getComputedStyle(el)[key]);
let speed = (target - current) / 10;
if (speed < 0) {
speed = Math.floor(speed);
} else {
speed = Math.ceil(speed);
}
el.style[key] = current + speed + "px";
// 判断所有属性是否都已经到达目标位置
if (current + speed == target) {
count++;
}
}
// 所有属性都到达目标位置时,清除定时器
if (count == Object.keys(obj).length) {
clearInterval(timer);
}
}, 200);
}