jby*_*yrd 4 html javascript css browser css-animations
根据我自己的经验,并与此答案一致,JavaScript 代码运行时不会对 UI 进行更改。
示例
当我单击“运行脚本”按钮时,我希望出现加载动画,然后我希望运行一些 JavaScript,当 JavaScript 运行完成时,我希望加载动画消失。我在这里创建了一个代码笔,它(可以预见)失败了。最相关的代码部分是:
$('#run-script-btn').on('click', function() {
startLoading();
longLoadingScript(10000);
stopLoading();
});
Run Code Online (Sandbox Code Playgroud)
startLoading()更改 CSS 以显示加载器,但它实际上不会影响 UI,直到 JS 完成运行,此时stopLoading()被调用 - 所以基本上我们从未看到加载图标。
我想出的解决方法是setTimeout()在longLoadingScript()和stopLoading()代码周围放置一个代码,以便让浏览器有时间实际影响startLoading()调用中的 UI 。工作代码在此处的 codepen 中,相关部分如下所示:
$('#run-script-btn').on('click', function() {
startLoading();
setTimeout(function() {
longLoadingScript(10000);
stopLoading();
}, 100);
});
Run Code Online (Sandbox Code Playgroud)
问题
这是一个好方法吗?是否有更好/更成熟的模式来处理这种情况?
这实际上发生在你的情况下,
1) 浏览器根据从您的服务器收到的 HTML 和 CSS创建渲染树。然后它将渲染树绘制到您的窗口。
2) 因此,当您对 DOM 进行任何更改时,例如显示更改(阻止/无)。渲染树的一部分(或完整)需要重新评估。这称为回流。
3) 浏览器缓存所有回流/重绘更改并在主代码块执行完成后执行。
4) 情况 1 - 没有 setTimeout:主代码块执行 + 回流/重绘所有更改。(显示:阻止然后无)。将看不到任何更改。
案例 2 - 使用 setTimeout:主代码块执行 + reflow(display: block) + 事件循环将 setTimeout 回调推送到调用堆栈 - reflow 将再次发生(display: none)
它也适用于 0 毫秒的 setTimeout。
回答您的问题:这对我来说看起来不错,我认为使用它没有任何问题。
$('#run-script-btn').on('click', function() {
startLoading();
setTimeout(function() {
longLoadingScript(100);
stopLoading();
}, 0);
});
Run Code Online (Sandbox Code Playgroud)
其他解决方案是使用 offsetHeight 重排元素。但是它似乎不适用于我的 chrome+osx 平台。在 Firefox 中运行良好。
$('#run-script-btn').on('click', function() {
startLoading();
var res = $('.page-loading').outerHeight(); // calculates offsetHeight and redraw the element
longLoadingScript(100);
stopLoading();
});
Run Code Online (Sandbox Code Playgroud)
参考:http : //frontendbabel.info/articles/webpage-rendering-101/