向DOM添加内容时,我需要等待多长时间(setTimeout)才能影响类更改?

The*_*ith 4 html javascript css

这是场景...我向DOM添加了一个元素,该元素的初始类具有0的不透明度,然后添加了一个类以触发不透明度过渡到1-一个很好的简单淡入。代码如下所示:

.test {
  opacity: 0;
  transition: opacity .5s;
}

.test.show {
  opacity: 1;
}
Run Code Online (Sandbox Code Playgroud)
const el = document.createElement('div')
el.textContent = 'Hello world!'
el.className = 'test' // <div class="test">Hello world!</div>
document.body.appendChild(el)
Run Code Online (Sandbox Code Playgroud)

现在要触发淡入,我只需将show类添加到元素中:

setTimeout(() => {
  el.classList.add('show')
}, 10)
Run Code Online (Sandbox Code Playgroud)

我使用的是setTimeout,因为如果不这样做,则将立即添加该类,并且不会发生淡入。它将最初在屏幕上可见,没有过渡。因此,我一直以来将10ms用于setTimeout,并且一直有效……直到现在。我遇到了需要将其设置为20ms的情况。有点脏 有人知道是否有安全的时间使用吗?我是否缺少有关DOM在这里的工作方式的信息?我知道我需要给浏览器一些时间来确定布局和绘画(因此setTimeout),但是要花多少时间呢?我感谢任何见识!

T.J*_*der 5

注意:看起来您可以避免添加第二个类来使元素淡入淡出,从而避免出现此计时问题,请参见silencedogood的答案。如果这对您有效,则似乎是一种比以下方法更好的方法。

如果由于某种原因对您不起作用,请继续阅读... :-)


我认为setTimeout您可以使用任何合理,安全的值。

相反,我将requestAnimationFrame在附加元素之后使用。在我的实验中,您需要等到第二个动画帧,如此粗略地讲:

requestAnimationFrame(function() {
    requestAnimationFrame(function() {
        el.classList.add("show");
    });
});
Run Code Online (Sandbox Code Playgroud)

现场示例:

requestAnimationFrame(function() {
    requestAnimationFrame(function() {
        el.classList.add("show");
    });
});
Run Code Online (Sandbox Code Playgroud)
document.getElementById("btn").addEventListener("click", function() {
    const el = document.createElement('div');
    el.textContent = 'Hello world!';
    el.className = 'test';
    document.body.appendChild(el);
    requestAnimationFrame(function() {
        requestAnimationFrame(function() {
            el.classList.add("show");
        });
    });
});
Run Code Online (Sandbox Code Playgroud)
.test {
  opacity: 0;
  transition: opacity .5s;
}

.test.show {
  opacity: 1;
}
Run Code Online (Sandbox Code Playgroud)

我的逻辑是,当您看到第一个动画帧时,您会知道DOM随元素一起呈现。因此,将类添加到第二个动画帧上在逻辑上应该在没有它的情况下进行渲染之后进行,从而触发过渡。

如果我在第一个动画帧中执行此操作,那么它对我在Firefox上无法可靠运行:

<input type="button" id="btn" value="Click me">
Run Code Online (Sandbox Code Playgroud)
document.getElementById("btn").addEventListener("click", function() {
    const el = document.createElement('div');
    el.textContent = 'Hello world!';
    el.className = 'test';
    document.body.appendChild(el);
    requestAnimationFrame(function() {
        //requestAnimationFrame(function() {
            el.classList.add("show");
        //});
    });
});
Run Code Online (Sandbox Code Playgroud)
.test {
  opacity: 0;
  transition: opacity .5s;
}

.test.show {
  opacity: 1;
}
Run Code Online (Sandbox Code Playgroud)

...这对我来说很有意义,因为它将在第一次渲染元素之前添加类。(如果我在页面加载中添加了元素,它确实起作用了,但是当我引入上面的按钮时却没有。)