当我想要让执行的javascript暂停,允许浏览器应用样式等操作后再继续时,我倾向于使用常见技术
在下面的代码片段中,我有一个将过渡效果应用于
当我悬停在目标 div 上时,我想从
如果我将内部 timeout 的延迟增加到
我本来希望任何
我使用的是macOS和Windows上的Chrome 56,尚未测试其他浏览器。(我知道我可以通过将过渡效果应用于仅
setTimeout
延迟 0
来在事件循环末尾排队回调。然而,我遇到一种情况,这种方法似乎不能可靠地工作。在下面的代码片段中,我有一个将过渡效果应用于
chaser
元素的 active
类。当我悬停在目标 div 上时,我想从
chaser
元素中删除 active
类,将 chaser
移动到新位置,然后重新应用 active
类。效果应该是 o
应立即消失,然后淡入到新位置。但实际上,opacity
和 top
都应用了过渡效果,因此 o
会从一个位置滑动到另一个位置,而不是立即消失,大部分时间都是这样。如果我将内部 timeout 的延迟增加到
10
,它就开始按照我的初衷行事。如果我将其设置为 5
,则有时会正常工作,有时不会。我本来希望任何
setTimeout
都会在应用样式更新后排队我的回调,但这里明显存在竞争条件。我错过了什么吗?有没有一种方法可以保证更新的顺序?我使用的是macOS和Windows上的Chrome 56,尚未测试其他浏览器。(我知道我可以通过将过渡效果应用于仅
opacity
属性等其他方式来实现此目的,请将此视为一个人为的例子,以说明关于排序样式更新的特定问题)。
var targets = document.querySelectorAll('.target');
var chaser = document.querySelector('#chaser');
for (var i = 0; i < targets.length; i++) {
targets[i].addEventListener('mouseenter', function(event) {
chaser.className = '';
setTimeout(function() {
// at this point, I'm expecting no transition
// to be active on the element
chaser.style.top = event.target.offsetTop + "px";
setTimeout(function() {
// at this point, I'm expecting the element to
// have finished moving to its new position
chaser.className = 'active';
}, 0);
}, 0);
});
}
#chaser {
position: absolute;
opacity: 0;
}
#chaser.active {
transition: all 1s;
opacity: 1;
}
.target {
height: 30px;
width: 30px;
margin: 10px;
background: #ddd;
}
<div id="chaser">o</div>
<div class="target">x</div>
<div class="target">x</div>
<div class="target">x</div>
<div class="target">x</div>
<div class="target">x</div>
setTimeout
没有按照我的期望进行操作,因为我过去一直依赖它,现在我想知道还有什么其他的可能出问题。 - CupawnTaerequestAnimationFrame
实验表明它大多数时候都有效,但并非总是如此。我猜第二个requestAnimationFrame
可能会实现一致性,但我认为这可能只是因为你基本上延迟了足够长的时间以避免竞争条件 - 我真的希望有些确定性的东西... - CupawnTae