requestAnimationframe和getComputedStyle ton n''
我正在观看并跟随杰克·阿奇博尔德(Jake Archibald)关于活动循环的演讲。在某个时候,他想将一个盒子移至1000px,然后返回500px。您还可以在此处观看视频:
jake acrachibald:in loop -jsconf.asia(22:10)(22:10)
他提供了两种解决方案,即使(我认为)我也做同样的事情,我也无法为我工作。第一个解决方案是:
button.addEventListener("click", () => {
box.style.transform = "translateX(1000px)";
box.style.transition = "transform 1s ease-in-out";
requestAnimationFrame(() => {
requestAnimationFrame(() => {
box.style.transform = "translateX(500px)";
});
});
});
正如他所说,第二个“ hacky”是:
button.addEventListener("click", () => {
box.style.transform = "translateX(1000px)";
box.style.transition = "transform 1s ease-in-out";
getComputedStyle(box).transform;
box.style.transform = "translateX(500px)";
});
在这两种情况下,盒子都移至500px,而首先则移至1000px,然后返回到500px。
我想念什么吗?我做错了吗?自2018年以来,事情发生了太大变化,以使该解决方案不再起作用?
PS我在Ubuntu上使用Chrome版本102.0.5005.61 22.04。
I am watching and following along Jake Archibald's speech about the Event Loop. At some point he attemps to move a box, first to 1000px and then back to 500px. You can also watch in the video here:
Jake Archibald: In The Loop - JSConf.Asia (22:10)
He offers two solutions and I couldn't get any of them to work for me, even though (I think) I am doing exactly the same. The first solution is this:
button.addEventListener("click", () => {
box.style.transform = "translateX(1000px)";
box.style.transition = "transform 1s ease-in-out";
requestAnimationFrame(() => {
requestAnimationFrame(() => {
box.style.transform = "translateX(500px)";
});
});
});
And the second "hacky" one, as he says, is this:
button.addEventListener("click", () => {
box.style.transform = "translateX(1000px)";
box.style.transition = "transform 1s ease-in-out";
getComputedStyle(box).transform;
box.style.transform = "translateX(500px)";
});
On both occasions the box just moves to 500px, while it should first move to 1000px and then back to 500px.
Am I missing something? Am I doing something wrong? Or have things changed that much since 2018 so that this solution doesn't work anymore?
P.S. I am using Chrome Version 102.0.5005.61 on Ubuntu 22.04.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
视频显示的是错误的。
对于此解释,我将使用“ hacky”方式,因为它似乎更容易理解,因为它是同步的,因此我们不必怀疑何时发生回流。 (如果您知道自己在做什么,实际上并没有比任何异步方式更骇客)。
为了过渡到工作,我们需要一个初始值,一个目的地和标志,告诉我们可以过渡给定的属性更改。
当升高此标志时,可以将其过渡值的任何更改都用作目的地,并且当前值将用作我们过渡的初始值。
在示例中,在单击按钮之前,我们只有一个初始值(
none
,即translatex(0px)
)。然后,我们设置了新的
转换
和transition
值。此时,CSS布局尚未更新,它不知道我们确实更改了任何内容。
下一行迫使回流,将解决这一问题。
在这里,CSS引擎可以看到它具有 transition flag
transform
提出的,并且transform
值已更改。因此,它启动了从当前值(0px
)的过渡到新的(1000px
)。但是,甚至在它开始渲染该过渡之前,
将目标更改为
500px
。因此,无论此时在哪里,它都会将过渡从更新到该新目标(500px
)。显然,异步版本也是如此,只是当我们将新值设置为
500px
时,我们的元素已经移动了一点(在60Hz监视器上〜17px,而它只能移动到其中一半)。这对于此值并不是很明显,因为它只是一个帧,而在单个帧中,速度差和1000px/s之间的速度差并不是很明显,但是如果您的差异更大,则可以看到它更好:
因此,我将再次在这里扮演“ Hacky”倡导者。使用同步方式,您确实可以控制发生的事情。只要非常小心,您就不会再污染CSS布局后不再污染回流了,您会没事的,浏览器不会在渲染步骤中重新计算它。
据我所记得的,这一直是预期和实际行为,我非常怀疑这是自从这次演讲以来发生的变化,您甚至可以在2019年的视频中检索一些评论,这些视频讨论了这一点,这些评论无法正如视频中所解释的那样起作用。
为了获得预期的行为,您需要在计算新的初始位置的回光后,将过渡与目标值的设置一起设置。
或者
What the video shows is wrong here.
For this explanation I will use the "hacky" way, since it seems easier to understand as it's synchronous and thus we don't have to wonder when the reflow happens. (And if you know what you're doing it's not actually more hacky than any async way).
For a transition to work, we need an initial value, a destination and a flag telling we're ok to transition a given property change.
When this flag is raised, any change to the value that can be transitioned will be used as the destination, and the current value will be used as the initial value of our transition.
In the example, before we click the button, we only have an initial value (
none
, i.etranslateX(0px)
).Then we set both the new
transform
andtransition
values.At this point, the CSS layout hasn't been updated, it doesn't know we did change anything.
The next line, which forces the reflow, will take care of that.
And here the CSS engine sees that it has the transition flag for
transform
raised AND that thetransform
value has changed. It thus initiates a transition from the current value (0px
) to the new one (1000px
).But even before it can start rendering that transition,
changes the destination to be
500px
. So it will update the transition to go from wherever it is at this point (still0px
) to that new destination (500px
).The same obviously happens with the async version, except that when we set the new value to
500px
our element will already have moved a bit (by ~17px on a 60Hz monitor, while it should have only moved by half of that).This isn't very noticeable with this value because it's only one frame and the speed difference between 500px/s and 1000px/s isn't very noticeable in a single frame, but if you have a much bigger difference, you can see it better:
So once again I'll play the "hacky" advocate here. Using the synchronous way, you do have control over what happens. Just be very careful that you don't pollute the CSS layout anymore after you've forced that reflow and you'll be fine, the browser won't recalculate it in the rendering step.
As far as I can remember this has always been the expected and actual behavior, I highly doubt this has changed since this talk and you can even retrieve some comments from 2019 under the video that talk about this not working as explained in the video.
To get the expected behavior, you'd need to set the transition along with the setting of the destination value, after the reflow that calculated the new initial position.
or