在代码中更新元素样式后,是否存在在视觉上更新之间的延迟?(JS)

huangapple go评论61阅读模式
英文:

Is there a delay between when an element style is updated in the code and updated visually? (JS)

问题

I created a bookmarklet (a browser bookmark that executes JavaScript instead of opening a webpage) that creates a "mousedown" event listener. When the listener is called it determines what element is under the mouse pointer, then if the element is text it changes the text color, alerts the user with some information, and when the alert is over reverts the text to its original color.

Here is the basic code:

document.addEventListener('mousedown', e => {
    const element = document.elementFromPoint(e.clientX, e.clientY);
    if (element is text) {
        const originalBackgroundColor = getComputedStyle(element).backgroundColor;
        const originalColor = getComputedStyle(element).color;
        element.style.backgroundColor = "yellow";
        element.style.color = "black";
        alert(some text);
        element.style.backgroundColor = originalBackgroundColor;
        element.style.color = originalColor;
    }
})

Problem:

Although the element style is updated before the alert is called, it doesn't appear to update on screen before the alert is displayed, so you cannot see a change.

I determined that there must be some delay between when the style is updated in the code and when it actually updates on-screen, so I tried implementing a setTimeout() function to combat this:

element.style.backgroundColor = "yellow";
element.style.color = "black";
setTimeout(() => {
    alert(some text);
    element.style.backgroundColor = originalBackgroundColor;
    element.style.color = originalColor;
}, 0)

This seems to work about 90% of the time, but occasionally some text will not visually update in time before the alert is displayed. I tried upping the delay time on the setTimeout() function to 10ms, which still doesn't always work. When I change it to 20ms it seems to always work, and I have determined that it is most likely because the screen refreshes every ~17ms (60fps), so a 20ms delay nearly guarantees the screen has refreshed before the alert is called.

However, just having a 20ms delay seems arbitrary and there is also a somewhat noticeable delay between when the text is clicked and when the alert is displayed.

Is there a better way to do this? Perhaps a way to wait exactly one frame before calling the alert? Or force the text to update visually before the alert is called?

Any help would be greatly appreciated.

英文:

I am new to JavaScript.

Context:
I created a bookmarklet (a browser bookmark that executes JavaScript instead of opening a webpage) that creates a "mousedown" event listener. When the listener is called it determines what element is under the mouse pointer, then if the element is text it changes the text color, alerts the user with some information, and when the alert is over reverts the text to its original color.
Here is the basic code:

document.addEventListener('mousedown', e => {
    const element = document.elementFromPoint(e.clientX, e.clientY);
    if (element is text) {
        const originalBackgroundColor = getComputedStyle(element).backgroundColor;
        const originalColor = getComputedStyle(element).color;
        element.style.backgroundColor = "yellow";
        element.style.color = "black";
        alert(some text);
        element.style.backgroundColor = originalBackgroundColor;
        element.style.color = originalColor;
    }
})

Problem:
Although the element style is updated before the alert is called, it doesn't appear to update on screen before the alert is displayed, so you cannot see a change.

I determined that there must be some delay between when the style is updated in the code and when it actually updates on-screen, so I tried implementing a setTimeout() function to combat this:

        element.style.backgroundColor = "yellow";
        element.style.color = "black";
        setTimeout(() => {
            alert(some text);
            element.style.backgroundColor = originalBackgroundColor;
            element.style.color = originalColor;
        }, 0)

This seems to work about 90% of the time, but occasionally some text will not visually update in time before the alert is displayed. I tried upping the delay time on the setTimeout() function to 10ms, which still doesn't always work. When I change it to 20ms it seems to always work, and I have determined that it is most likely because the screen refreshes every ~17ms (60fps), so a 20ms delay nearly guarantees the screen has refreshed before the alert is called.
However, just having a 20ms delay seems arbitrary and there is also a somewhat noticeable delay between when the text is clicked and when the alert is displayed.

Is there a better way to do this? Perhaps a way to wait exactly one frame before calling the alert? Or force the text to update visually before the alert is called?
Any help would be greatly appreciated.

答案1

得分: 2

你可能希望查看 requestAnimationFrame()。来自 MDN 的说明如下:
> 这将请求在浏览器执行下一次重绘之前调用您的动画函数

您希望在下一次重绘之后运行您的代码,因此您可以在 requestAnimationFrame 中嵌套一个 setTimeout(..., 0) 调用。例如:

document.addEventListener('mousedown', e => {
    const element = document.elementFromPoint(e.clientX, e.clientY);
    if (element is text) {
        const originalBackgroundColor = getComputedStyle(element).backgroundColor;
        const originalColor = getComputedStyle(element).color;
        element.style.backgroundColor = "yellow";
        element.style.color = "black";
        requestAnimationFrame(() => {
            setTimeout(() => {
                alert(some text);
                element.style.backgroundColor = originalBackgroundColor;
                element.style.color = originalColor;
            }, 0)
        })
    }
})
英文:

You might want to look into requestAnimationFrame(). From MDN:
> This will request that your animation function be called before the browser performs the next repaint

You want to run your code after the next repaint, so you can nest a setTimeout(..., 0) call within your requestAnimationFrame. For example:

document.addEventListener('mousedown', e => {
    const element = document.elementFromPoint(e.clientX, e.clientY);
    if (element is text) {
        const originalBackgroundColor = getComputedStyle(element).backgroundColor;
        const originalColor = getComputedStyle(element).color;
        element.style.backgroundColor = "yellow";
        element.style.color = "black";
        requestAnimationFrame(() => {
            setTimeout(() => {
                alert(some text);
                element.style.backgroundColor = originalBackgroundColor;
                element.style.color = originalColor;
            }, 0)
        })
    }
})

huangapple
  • 本文由 发表于 2023年5月20日 23:40:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76296032.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定