14

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

  1. 将父容器的不透明度设置为 0。
  2. 将内容插入 DOM。
  3. 测量尺寸,例如$el.outerWidth(true)
  4. 根据这些尺寸定位内容。
  5. 将父容器的不透明度(背面)设置为 1.0。

这种方法的问题是内容非常复杂并且包含图像。调用时outerWidth(),浏览器尚未完成重新绘制屏幕,​​因此返回的尺寸不准确。(有趣的是,在我的情况下,初始尺寸总是明显大于最终值,而不是我预期的 0。)

我可以通过在第 2 步和第 3 步之间设置一个计时器来减少问题,但无论我设置多长时间,某些系统上的某些浏览器肯定会超过它。如果我让计时器足够长以涵盖大多数情况,那将通过引入不必要的延迟来惩罚使用更快系统的用户。尽管下面引用的一些答案表明 asetTimeout(fn, 0)就足够了,但我发现情况并非如此。我在 2012 款 MacBook Air 上测得的绘制时间高达 60 毫秒,下面的一个答案建议 500 毫秒。

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

非常感谢解决方案或意见。如下所述,这个问题之前已经被问过,但大多数问题至少有一年的历史了,我非常渴望再试一次。


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


更新:好吧,看来这个问题根本没有通用的解决方案。在我的具体情况下,我发现一旦加载内容并完成布局,该属性就会可靠地改变。JavaScript 轮询此属性的更改。一点也不优雅,但这是我能找到的最佳选择。

4

2 回答 2

0

我已经开始研究目前的情况,我的解决方案是:

doSomeDomManipulation();
requestAnimationFrame(() => {
  setTimeout(() => {
    alert("finished painting");
  }, 0);
});

这种方法的来源:

这曾经在旧 MDN 页面上关于 MozAfterPaint 主题的注释中

“想要在页面重绘后采取行动的网页可以使用 requestAnimationFrame 和一个将超时设置为零的回调,然后调用执行所需的重绘后操作的代码。”

于 2021-10-11T16:39:01.907 回答
-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 小提琴

于 2013-11-02T01:20:51.247 回答