首页 > 解决方案 > MutationObserver 知道何时在 HTML 中计算和渲染样式

问题描述

所以我创造了一些东西,我需要能够在有和没有过渡的情况下转换一些元素。

假设我必须在没有过渡的情况下转换某些东西,然后我当然首先从元素中删除转换参数(如果有的话),每当我知道转换样式消失时,我想转换元素。也许在那之后我想再次转换元素,但这次有一些过渡。所以首先,我添加了过渡,只要准备好了,我就会变换元素。

我创建了一个函数“setStyle”,它应该处理给定元素的样式设置,然后在该样式实际添加到视图时解析。我试图在 MutationObserver 的帮助下这样做。但是我显然误解了这点,或者 MutationObserver 的用例。

我创建了一个带有函数“setStyle”的简单 CodePen,我在其中演示了我首先使用该函数来设置转换样式属性,并且由于尚未添加转换属性,因此不应该进行转换。在我添加了转换属性之后,我添加了转换属性,但在这个代码示例中,看起来这两个属性是同时应用的。

为什么我不只使用“setTimeout”?“setTimeout”不是保证,我想做一些适用于任何 Web API 的事情。

https://codepen.io/herman-jansson/pen/NWNKWXL

<button id="start">Start</button>
<div id="div">

</div>
var elem = document.getElementById('div');

var setStyle = (element, style, value) => {
    return new Promise(resolve => {
      const observer = new MutationObserver((mutations) => {
        if(
          document.contains(element) 
          && 
          mutations.some((mutation) => !!mutation.attributeName)
        ) {
          // style should be added here, but most likely not calculated since 
          // its not working
          observer.disconnect();
          resolve();
        }
      })
       observer.observe(element, { attributes: true, attributeFilter: ["style"]});
       element.style[style] = value;
    });
}


document.getElementById('reset').addEventListener('click', () => {
    setStyle(elem, 'transform', 'translateX(-50%)').then(() => {
      setStyle(elem, 'transition', 'transform 1s ease-in-out')
    });
});

标签: javascriptanimationstylingevent-loopmutation-observers

解决方案


虽然属性确实style在两个离散的步骤中更新(如通过向 MutationObserverMutationObserver只是看到属性已更新(但如果渲染引擎应用了更改,则不会)并立即解决。当渲染引擎开始对style更改采取行动时,这两项更改都已完成,并被视为同一更新的一部分。

style一种解决方案是在两个属性更新之间自行触发回流。(这通常不是您想要做的事情,因为它会使页面的响应速度降低,因此应慎重应用。)通常,(直接或间接)读取元素的计算尺寸或位置会导致重排. 这个要点列出了一些已知会导致立即回流的属性和函数。

总而言之,添加一个类似element.offsetLeft;这样的行以便在两个样式更新之间执行它可能看起来什么都不做,但会导致回流作为副作用。这反过来会导致渲染引擎将这两个style更改视为单独的更新。

我相信您甚至可以删除该setStyle功能并使用:

elem.style.transform = 'translateX(-50%)';
elem.offsetLeft;
elem.style.transition = 'transform 1s ease-in-out';

推荐阅读