如何确定浏览器何时完成绘制插入的元素
How to determine when a browser has finished painting an inserted element?
我有一个网页注入了通过AJAX交付的HTML。我不知道,先验地,内容的大小,但我需要根据其大小将内容定位在页面上。这是一个行不通的简单方法:
- 将父容器的不透明度设置为 0。
- 将内容插入到 DOM 中。
- 测量尺寸,例如
$el.outerWidth(true)
. - 根据这些大小定位内容。
- 将父容器的不透明度(向后)设置为 1.0。
这种方法的问题在于内容非常复杂并且包含图像。调用 outerWidth()
时,浏览器尚未完成重新绘制屏幕,因此返回的大小不准确。(有趣的是,在我的情况下,初始维度总是明显大于阈值,而不是我预期的 0。
我可以通过在步骤 2 和 3 之间设置计时器来减少问题,但无论我制作计时器多长时间,某些系统上肯定会有一些浏览器超过它。如果我使计时器足够长以涵盖大多数情况,这将通过引入不必要的延迟来惩罚使用更快系统的用户。尽管下面引用的一些答案表明setTimeout(fn, 0)
就足够了,但我发现情况并非如此。我在 2012 年的 MacBook Air 上测量的绘画时间高达 60 毫秒,下面的一个答案是 500 毫秒。
看起来 Mozilla 曾经有一个onPaint
事件,可能已经解决了我的问题......如果它仍然存在并且其他浏览器已采用它。(这两种情况都不是。突变观察者在报告元素变化时似乎没有考虑绘画时间。
非常感谢解决方案或评论。如下所述,这之前已经问过了,但大多数问题至少已经存在了一年,我很想再试一次。
不幸的是,没有提供可行答案的相关问题
- 如何检测图像何时在浏览器中完成渲染(即绘制)?
- jQuery - 一旦我们知道 ajax 加载元素的真实高度(带有图像),如何立即执行脚本?
- 追加后立即DIV宽度计算错误?
- jQuery 在追加元素后立即返回div 元素的高度 0
- Javascript:无法获取新创建的元素的高度
- jQuery:为什么 .width() 有时会在插入带有 .html() 的元素后返回 0?
更新:好吧,似乎根本没有解决此问题的通用解决方案。在我的特定情况下,我找到了一个属性,一旦加载内容并完成布局,该属性就会可靠地更改。JavaScript 轮询此属性的更改。一点也不优雅,但这是我能找到的最好的选择。
我已经开始研究这种情况的现状,我的解决方案是这样的:
doSomeDomManipulation();
requestAnimationFrame(() => {
setTimeout(() => {
alert("finished painting");
}, 0);
});
此方法的来源:
这曾经在旧的MDN页面上关于MozAfterPaint主题的注释中:
"想要在重新绘制页面后执行操作的网页可以使用带有回调的 requestAnimationFrame,该回调将超时设置为零,然后调用执行所需的重绘后操作的代码。"
编辑:一个更好的版本,使用queueMicrotask
而不是setTimeout
(setTimeout
将宏任务排队,稍后会运行):
doSomeDomManipulation();
requestAnimationFrame(() => {
queueMicrotask(() => {
alert("finished painting");
});
});
您可以查看窗口加载是否可以解决问题。我不确定它是否触发了不止一次,何时加载新内容,或者不触发。
但是对于图像,您可以使用这样的东西。
匹配图像加载完成后调用函数
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小提琴加载的图像
- jQuery/Javascript在内容可编辑的当前段落后插入元素
- 尝试在元素之前插入元素的结果
- 使用java脚本在html中插入元素
- ()插入元素,然后将其取回
- 在子字符串前后插入元素
- 将语法代码插入“
”元素时,ckeditor 会自动关闭标记
- D3.js - 根据当前基准面追加或插入元素
- 初学者 - 尝试让 jQuery 插入元素
- 在插入元素后在 ckeditor 中创建书签 2
- Javascript - 在脚本位置插入元素
- JavaScript 在执行点插入元素
- 通过javascript插入元素,而不会丢失jquery移动样式页面
- 使用jQuery设置插入元素的动画
- Mongoose如何在现有对象(MongoDB和Node.js)上插入元素
- jquery自动完成具有未知id的动态插入元素
- 在停止元素的同时插入元素的确认行为'的其他事件处理程序
- 动态插入元素的CSS
- 使用jQuery在祖先和后代之间插入元素
- 如何在ember js中插入元素后获得通知
- 在第n个位置插入元素