我正在使用jQuery来更改标记的HTML,而新的HTML可能是一个非常长的字符串。
$("#divToChange").html(newHTML);
然后我想选择在新HTML中创建的元素,但是如果我将代码紧跟在上面的行之后,它似乎创建了一个带有长字符串的竞争条件,其中html()所做的更改可能不一定是完成渲染。在这种情况下,尝试选择新元素并不总是有效。
我想知道的是,当html()的更改完成渲染时,是否有一个事件被触发或者有其他方式被通知?我遇到了jQuery手表插件,它可以正常工作,但它并不理想。有没有更好的办法 ?
答案 0 :(得分:6)
作为一名已经提到的评论者,JavaScript是单线程的,因此您无法获得竞争条件。
然而,可能会让你失望的是,在线程完成之前,UI不会基于JavaScript更新自身。这意味着在浏览器呈现内容之前,必须完成整个方法,包括调用html(...)
后的所有代码。
如果您在调用html(...)
后的代码依赖于重新计算的页面布局,那么您可以执行以下操作:
$("#divToChange").html(newHTML);
setTimeout(function() {
// Insert code to be executed AFTER
// the page renders the markup
// added using html(...) here
}, 1);
在JavaScript中使用时间为setTimeout(...)
的{{1}}推迟执行,直到调用函数中的当前JavaScript代码完成并且浏览器更新了UI。这可能会解决您的问题,但除非您能提供可重现的错误示例,否则很难说明问题。
答案 1 :(得分:1)
这是7年后,我刚刚遇到了一个与@mikel所描述的情况完全相同的情况,在那里我无法避免“基于计时器的解决方案”。所以,我只是分享我开发的解决方案,以防任何人在那里仍有问题。
我讨厌在我的代码中使用setTimeout
和setInterval
s。所以,我创建了一个小插件,你可以把它放在你认为最好的地方。我使用了setInterval
,但您可以将其更改为setTimeout或其他解决方案。这个想法只是创建一个承诺并继续检查元素。一旦准备好,我们就会解决这个承诺。
// jquery.ensure.js
$.ensure = function (selector) {
var promise = $.Deferred();
var interval = setInterval(function () {
if ($(selector)[0]) {
clearInterval(interval);
promise.resolve();
}
}, 1);
return promise;
};
// my-app.js
function runWhenMyElementExists () {
// run the code that depends on #my-element
}
$.ensure('#my-element')
.then(runWhenMyElementExists);
答案 2 :(得分:0)
使用.ready jQuery函数
$("#divToChange").html(newHTML).ready(function () {
// run when page is rendered
});