12

我正在使用 jQuery 来更改标签的 HTML,而新的 HTML 可以是很长的字符串。

$("#divToChange").html(newHTML);

然后我想选择在新 HTML 中创建的元素,但是如果我将代码紧跟在上面的行之后,它似乎会创建一个带有长字符串的竞争条件,其中 html() 所做的更改可能不一定完成渲染。在这种情况下,尝试选择新元素并不总是有效。

我想知道的是,当对 html() 的更改完成渲染时,是否会触发事件或以其他方式通知?我遇到了 jQuery watch 插件,它可以作为解决方法使用,但并不理想。有没有更好的办法 ?

4

3 回答 3

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(...)time 会1延迟执行,直到调用函数中的当前 JavaScript 代码完成并且浏览器更新了 UI。这可能会解决您的问题,尽管除非您能提供一个可重现的错误示例,否则很难说清楚。

于 2010-04-03T02:55:24.237 回答
1

使用 .ready jQuery 函数

$("#divToChange").html(newHTML).ready(function () {
                    // run when page is rendered
                    });
于 2020-10-19T14:45:54.840 回答
1

7 年后,我遇到了与@mikel 描述的完全一样的场景,我无法避免“基于计时器的解决方案”。所以,我只是分享我开发的解决方案,以防有人仍然有这个问题。

我讨厌在我的代码中有setTimeouts 和s 。setInterval所以,我创建了一个小插件,你可以把它放在你认为最好的地方。我使用过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);
于 2018-01-10T16:20:26.170 回答