setTimeout()
只能因竞争条件,requestAnimationFrame()
应改为使用。但是offsetWidth
,在所有选项中,这种技巧最有效。
这是一个示例情况。我们有一系列的框,每个框需要按顺序向下动画。为了使一切正常工作,我们需要为每个元素获取两次动画帧,这里我在动画之前放置了一次,在动画之后放置了一次,但是如果将它们一个接一个放置,这似乎也可以工作。
使用requestAnimationFrame
两次有效:
无论2 getFrame()
s和单个set-class-name步骤的排序顺序如何,都可以使用。
const delay = (d) => new Promise(resolve => setTimeout(resolve, d));
const getFrame = () => new Promise(resolve => window.requestAnimationFrame(resolve));
async function run() {
for (let i = 0; i < 100; i++) {
const box = document.createElement('div');
document.body.appendChild(box);
await getFrame();
box.className = 'move';
await getFrame();
}
}
run();
div {
display: inline-block;
background-color: red;
width: 20px;
height: 20px;
transition: transform 1s;
}
.move {
transform: translate(0px, 100px);
}
使用setTimeout
两次失败:
由于这是基于比赛条件的,因此确切的结果会因您的浏览器和计算机而相差很大。增加setTimeout
延迟会帮助动画更频繁地赢得比赛,但不能保证任何效果。
在我的Surfacebook 1上使用Firefox,并且延迟2ms / el,我发现大约50%的盒子出现故障。以20ms / el的延迟,我看到大约10%的包装盒失效。
const delay = (d) => new Promise(resolve => setTimeout(resolve, d));
const getFrame = () => new Promise(resolve => window.requestAnimationFrame(resolve));
async function run() {
for (let i = 0; i < 100; i++) {
const box = document.createElement('div');
document.body.appendChild(box);
await delay(1);
box.className = 'move';
await delay(1);
}
}
run();
div {
display: inline-block;
background-color: red;
width: 20px;
height: 20px;
transition: transform 1s;
}
.move {
transform: translate(0px, 100px);
}
通常使用requestAnimationFrame
一次即可setTimeout
:
这是布伦丹的解决方案(setTimeout
第一)或庞伯的解决方案(requestAnimationFrame
第一)。
getFrame()
delay(0)
ANIMATE
delay(0)
getFrame()
ANIMATE
delay(0)
ANIMATE
getFrame()
getFrame()
ANIMATE
delay(0)
一次不起作用的情况(对我而言)是在获取帧时进行动画处理,然后进行延迟。我没有解释为什么。
const delay = (d) => new Promise(resolve => setTimeout(resolve, d));
const getFrame = () => new Promise(resolve => window.requestAnimationFrame(resolve));
async function run() {
for (let i = 0; i < 100; i++) {
const box = document.createElement('div');
document.body.appendChild(box);
await getFrame();
await delay(1);
box.className = 'move';
}
}
run();
div {
display: inline-block;
background-color: red;
width: 20px;
height: 20px;
transition: transform 1s;
}
.move {
transform: translate(0px, 100px);
}