我已经检查了主题JavascriptappendChild回调?。在那里,目标元素是
video
,因此使用 loadedmetadata 是这种情况的解决方案。
就我而言,有小吃店,但它只是一个
div
。
我预计下面的代码会将小吃栏附加到
body
,然后将CSS类Snackbar-Transition__HiddenState
替换为Snackbar-Transition__DisplayingState
,这将触发CSS转换。
document.querySelector("body").appendChild(snackbar);
snackbar.style.transitionDuration = `${ displayingDuration__seconds }s`;
snackbar.classList.remove("Snackbar-Transition__HiddenState");
snackbar.classList.add("Snackbar-Transition__DisplayingState");
与预期相反,转变是即时的:
但是,如果我们在
appendChild
之后添加延迟,过渡将会很平滑:
document.querySelector("body").appendChild(snackbar);
setTimeout(
() => {
snackbar.style.transitionDuration = `${ displayingDuration__seconds }s`;
snackbar.classList.remove("Snackbar-Transition__HiddenState");
snackbar.classList.add("Snackbar-Transition__DisplayingState");
},
500
);
这不是解决方案,因为我们不知道延迟必须是多少。 大延迟会让人感觉应用程序滞后,而小延迟(几毫秒)可能还不够。这是当需要回调
appendChild
但没有这样的回调时的情况。可以用什么代替?
发生的情况是浏览器在宏任务完成后重新渲染页面(JS 在某个事件后结束工作)。
document.querySelector("body").appendChild(snackbar);
snackbar.style.transitionDuration = `${ displayingDuration__seconds }s`;
snackbar.classList.remove("Snackbar-Transition__HiddenState");
snackbar.classList.add("Snackbar-Transition__DisplayingState");
您在这里所做的是添加元素,更改其类,因此当您完成后,浏览器会看到一个新添加的元素,就是这样,浏览器不知道该元素之前的状态,因此无法推断出任何转换。
当您将
setTimeout
添加到等式中时,您允许浏览器捕获 CSS 类更改。你可以把延迟设置为0
,这里没问题。
为了流畅的性能(没有
setTimeout()
),你可以使用requestAnimationFrame
,它在所有同步JS代码和所有微任务完成后执行,这样浏览器就知道DOM的最终状态,你可以在重新渲染之前改变它页码:
async function show(){
const snackbar = document.createElement('div');
snackbar.classList.add("Snackbar-Transition__HiddenState", 'Snackbar');
snackbar.innerHTML = ' ';
document.querySelector("body").appendChild(snackbar);
requestAnimationFrame(() => {
console.log('animation frame');
snackbar.classList.remove("Snackbar-Transition__HiddenState");
snackbar.classList.add("Snackbar-Transition__DisplayingState");
});
queueMicrotask(() => console.log('i am a microtask'));
}
.Snackbar{
width: 128px;
height: 32px;
background: blue;
position: absolute;
left: 50%;
margin-left: -64px;
transition: top 500ms;
}
.Snackbar-Transition__HiddenState{
top: -32px;
}
.Snackbar-Transition__DisplayingState{
top: 64px;
}
<button onclick="show()">Show</button>