如何确定浏览器何时完成绘制插入元素?

时间:2013-11-02 00:54:24

标签: javascript

我有一个网页,它注入了通过AJAX提供的HTML。我不知道,先验,内容的大小,但我需要根据内容的大小在页面上定位内容。这是一个不起作用的简单方法:

  1. 将父容器的不透明度设置为0.
  2. 将内容插入DOM。
  3. 测量尺寸,例如$el.outerWidth(true)
  4. 根据这些尺寸定位内容。
  5. 将父容器的不透明度(后退)设置为1.0。
  6. 这种方法的问题在于内容非常复杂并且包含图像。调用outerWidth()时,浏览器尚未完成重新绘制屏幕,​​因此返回的尺寸不准确。 (有趣的是,在我的情况下,初始尺寸总是远远大于最终值,而不是我预期的0.)

    我可以通过在步骤2和3之间设置一个计时器来减少问题,但无论我做多长时间计时器,某些系统上肯定会有一些浏览器会超过它。如果我让计时器足够长以覆盖大多数情况,那将通过引入不必要的延迟来惩罚使用更快系统的用户。虽然下面引用的一些答案表明setTimeout(fn, 0)已经足够,但我发现情况并非如此。我在2012年MacBook Air上测量的喷涂时间高达60毫秒,下面的一个答案表明500毫秒。

    看起来Mozilla曾经有onPaint event可能解决了我的问题......如果它仍然存在并且其他浏览器已经采用了它。 (两者都不是这种情况。)并且Mutation Observers似乎没有考虑报告元素变化时的绘画时间。

    非常感谢解决方案或评论。如下所述,之前已经提出过这个问题,但大多数问题都至少有一年了,而且我很想再试一次。


    不幸的是,相关问题没有提供可行的答案


    更新:好吧,似乎根本没有针对这个问题的一般解决方案。在我的特定情况下,我发现一个属性在内容加载和布局完成后可以可靠地更改。 JavaScript轮询此属性的更改。一点也不优雅,但这是我能找到的最佳选择。

1 个答案:

答案 0 :(得分:-1)

你可以看到窗口加载是否可以解决问题。当加载新内容时,我不确定它是否会多次触发。

但是对于图像,你可以使用这样的东西。

//在匹配的图像加载完毕后调用函数

function imagesLoadedEvent(selector, callback) {
    var This = this;
    this.images = $(selector);
    this.nrImagesToLoad = this.images.length;
    this.nrImagesLoaded = 0;

    //check if images have already been cached and loaded
    $.each(this.images, function (key, img) {
        if (img.complete) {
            This.nrImagesLoaded++;
        }
        if (This.nrImagesToLoad == This.nrImagesLoaded) {
            callback(This.images);
        }
    });

    this.images.load(function (evt) {
        This.nrImagesLoaded++;
        if (This.nrImagesToLoad == This.nrImagesLoaded) {
            callback(This.images);
        }
    });
}

$("#btn").click(function () {
    var c = $("#container"), evt;
    c.empty();
    c.append("<img src='" + $("#img1").val() + "' width=94>");
    c.append("<img src='" + $("#img2").val() + "' width=94>");
    c.append("<img src='" + $("#img3").val() + "' width=94>");
    evt = new imagesLoadedEvent("img", allImagesLoaded);
});

function allImagesLoaded(imgs) {
    //this is called when all images are loaded
    //console.log("all " + imgs.length + " images loaded");
}

js fiddle for images loaded