我在做什么,哪里出了问题
当我点击一个按钮时,会出现一个 slider 。 ( here is an example of what it looks like , 不要关注这段代码)
slider 通过动画显示。动画完成后,我应该包含一个从服务器加载的 HTML 页面。我需要在动画之后在 slider 中应用 HTML,否则动画将停止(重新计算 DOM)。
我的算法
- 启动请求以获取要在 slider 内显示的 HTML
- 开始动画
等待数据准备好和转换完成
为什么?如果我在动画期间应用 HTML,它会在新 HTML 添加到 DOM 时停止动画。所以我在第 4 步之前等待两者都结束。
- 在 slider 内应用 HTML
这里是缩短的代码:
// Start loading data & animate transition
var count = 0;
var data = null;
++count;
$.get(url, function (res) {
data = res;
cbSlider();
});
// Animation starts here
++count;
$(document).on('transitionend', '#' + sliderId, function () {
$(document).off('transitionend', '#' + sliderId);
cbSlider()
});
function cbSlider() {
--count;
// This condition is only correct when both GET request and animation are finished
if (count == 0) {
// Attempt to enforce the frame to finish (doesn't work)
window.requestAnimationFrame(() => { return });
$('#' + sliderId + ' .slider-content').html(data);
}
}
详细问题
transitionend
过早调用。它使最后一个动画帧太长(477.2 毫秒)并且在 transitionend
事件中最后一帧未呈现。
从 Google 文档中,我可以告诉您 Pixel Pipeline 的 Paint 和 Composite 步骤在Event(transitionend)
之后调用:
也许我想多了。
我应该如何处理这种动画?
如何等待动画完全完成并渲染?
最佳答案
我不确定为什么 transitionend
在最后一帧渲染之前被触发,但在这个(非常粗糙的)测试中似乎 setTimeout
确实 帮助...
第一个示例显示了 html 计算和注入(inject)是如何过早发生的。第二个示例将长时间运行的方法包装在 setTimeout
中,并且似乎没有触发动画中的任何中断。
示例 1:重现您的问题
var ended = 0;
var cb = function() {
ended += 1;
if (ended == 2) {
$(".animated").html(createLongHTMLString());
}
}
$(".load").click(function() {
$(".animated").addClass("loading");
$(".animated").on("transitionend", cb);
setTimeout(cb, 100);
});
function createLongHTMLString() {
var str = "";
for (var i = 0; i < 100000; i += 1) {
str += "<em>Test </em>";
}
return str;
};
.animated,
.target {
width: 100px;
height: 100px;
position: absolute;
text-align: center;
line-height: 100px;
overflow: hidden;
}
.target,
.animated.loading {
transform: translateX(300%);
}
.animated {
background: green;
z-index: 1;
transition: transform .2s linear;
}
.target {
background: red;
z-index: 0;
}
.wrapper {
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="animated">Loading</div>
<div class="target"></div>
</div>
<button class="load">load</button>
示例 2:其中 setTimeout
似乎可以修复它
用 setTimeout
围绕 html 注入(inject)代码。
var ended = 0;
var cb = function() {
ended += 1;
if (ended == 2) {
setTimeout(function() {
$(".animated").html(createLongHTMLString());
});
}
}
$(".load").click(function() {
$(".animated").addClass("loading");
$(".animated").on("transitionend", cb);
setTimeout(cb, 100);
});
function createLongHTMLString() {
var str = "";
for (var i = 0; i < 100000; i += 1) {
str += "<em>Test </em>";
}
return str;
};
.animated,
.target {
width: 100px;
height: 100px;
position: absolute;
text-align: center;
line-height: 100px;
overflow: hidden;
}
.target,
.animated.loading {
transform: translateX(300%);
}
.animated {
background: green;
z-index: 1;
transition: transform .2s linear;
}
.target {
background: red;
z-index: 0;
}
.wrapper {
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="animated">Loading</div>
<div class="target"></div>
</div>
<button class="load">load</button>
关于javascript - 事件 'transitionend' 被调用得太早,它延迟渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39167044/