如何判断动态创建的元素何时呈现

fun*_*bro 46 javascript dom

我需要准确测量我的Web应用程序中文本的维度,我通过创建一个元素(具有相关的CSS类)来实现,innerHTML然后设置它然后使用它将其添加到容器中appendChild.

执行此操作后,在元素呈现之前有一个等待,offsetWidth可以读取它以找出文本的宽度.

目前,我正在setTimeout(processText, 100)等待渲染完成.

是否有我可以收听的回调,或者更可靠的方式告诉我创建的元素何时被渲染?

mys*_*dat 39

目前没有DOM事件表明元素已经完全呈现(例如,附加的CSS应用和绘制).这可能会使一些DOM操作代码返回错误或随机结果(如获取元素的高度).

使用setTimeout为浏览器提供一些渲染开销是最简单的方法.运用

setTimeout(function(){}, 0)
Run Code Online (Sandbox Code Playgroud)

可能是最实际的准确,因为它将您的代码放在活动浏览器事件队列的末尾而没有任何延迟 - 换句话说,您的代码在渲染操作之后排队(以及当时发生的所有其他操作).

  • 值得指出的是,有时你需要传递一段时间.我有一个问题,试图获取容器的滚动高度,该属性有时为0,有时是正确的.添加500毫秒的延迟来获取此属性修复了该问题. (2认同)
  • 我认为这个答案在没有完全真实的情况下被接受了。OP 要求“渲染事件”,这(理论上,如果它有效)只能让您知道该元素位于 DOM 中,但并不是所有渲染都已完成。我想知道 [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) 是否会做所需的事情? (2认同)
  • 这些都不适用于慢速机器。甚至 ResizeObserver 也不起作用。它也是在错误的时刻触发的。最后我不得不选择 150 毫秒延迟选项:( 浏览器错误?(chrome os 98) (2认同)

Ell*_* B. 27

接受的答案是从2014年开始,现在已经过时了.A setTimeout可能有效,但它不是最干净的,并不一定能保证元素已添加到DOM中.

今天,您应该使用MutationObserver来检测何时将元素添加到DOM.现在,MutationObservers在所有现代浏览器(Chrome 26 +,Firefox 14 +,IE11,Edge,Opera 15+等)中得到广泛支持.

将元素添加到DOM后,您将能够检索其实际尺寸.

这是一个简单的示例,说明如何MutationObserver在将元素添加到DOM时使用a 来监听.

为简洁起见,我使用jQuery语法构建节点并将其插入DOM.

var myElement = $("<div>hello world</div>")[0];

var observer = new MutationObserver(function(mutations) {
   if (document.contains(myElement)) {
        console.log("It's in the DOM!");
        observer.disconnect();
    }
});

observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});

$("body").append(myElement); // console.log: It's in the DOM!
Run Code Online (Sandbox Code Playgroud)

observer每当添加或删除任何节点时,事件处理程序都将触发document.在处理程序内部,我们然后执行contains检查以确定myElement现在是否在document.

您不需要遍历存储的每个MutationRecord,mutations因为您可以document.contains直接执行检查myElement.

要提高性能,请document使用myElementDOM中包含的特定元素替换.

  • 这在文本呈现的情况下不起作用. (2认同)
  • 带有文本的事情是渲染 dom 元素,然后文本进一步改变观察者已经输入到 if 语句的文本,因此观察者持有初始快照。它可能只是一个镀铬的东西。没有把握 (2认同)
  • OP想要元素被“渲染”的时间。当突变记录触发时,您可以非常确定该元素尚未渲染。是的,它在 DOM 中,但您只是同步调用 append() 后的一个微任务,并且渲染器还没有机会启动。`setTimeout()` 确实不是一个好的解决方案,但它必须比突变记录更接近渲染。如果他们只想知道元素何时位于 DOM 中,那么很简单:在调用append() 之后。 (2认同)

Rob*_*ene 17

就我而言,解决方案如setTimeoutMutationObserver并不完全可靠。相反,我使用了ResizeObserver。根据MDN

如果遵循规范,实现应该在绘制之前和布局之后调用调整大小事件。

所以基本上观察者总是在布局后触发,因此我们应该能够获得观察到的元素的正确尺寸。作为奖励,观察者已经返回了元素的尺寸。因此我们甚至不需要调用类似的东西offsetWidth(尽管它也应该有效)

const myElement = document.createElement("div");
myElement.textContent = "test string";

const resizeObserver = new ResizeObserver(entries => {
  const lastEntry = entries.pop();

  // alternatively use contentBoxSize here
  // Note: older versions of Firefox (<= 91) provided a single size object instead of an array of sizes
  // https://bugzilla.mozilla.org/show_bug.cgi?id=1689645
  const width = lastEntry.borderBoxSize?.inlineSize ?? lastEntry.borderBoxSize[0].inlineSize;
  const height = lastEntry.borderBoxSize?.blockSize ?? lastEntry.borderBoxSize[0].blockSize;

  resizeObserver.disconnect();

  console.log("width:", width, "height:", height);
});

resizeObserver.observe(myElement);

document.body.append(myElement);
Run Code Online (Sandbox Code Playgroud)

我们也可以将其包装在一个方便的异步函数中,如下所示:

function appendAwaitLayout(parent, element) {
  return new Promise((resolve, reject) => {
    const resizeObserver = new ResizeObserver((entries) => {
      resizeObserver.disconnect();
      resolve(entries);
    });

    resizeObserver.observe(element);

    parent.append(element);
  });
}

// call it like this
appendAwaitLayout(document.body, document.createElement("div")).then((entries) => {
  console.log(entries)
  // do stuff here ...
});
Run Code Online (Sandbox Code Playgroud)


Yuv*_* A. 13

这篇博文由Swizec Teller撰写,建议使用requestAnimationFrame并检查size元素.

function try() {
    if (!$("#element").size()) {
        window.requestAnimationFrame(try);
    } else {
        $("#element").do_some_stuff();
    }
};
Run Code Online (Sandbox Code Playgroud)

在实践中它只会重试一次.因为无论如何,在下一个渲染帧中,无论是60秒还是一分钟,元素都将被渲染.

  • `try`关键字如何处理?您没有错误吗? (2认同)

小智 5

MutationObserver可能是最好的方法,但这是一个可行的简单选择

我有一些JavaScript,可为大型表格构建HTML,并将div的innerHTML设置为生成的HTML。如果Date()在设置innerHTML之后立即获取,则发现时间戳是在表格完全呈现之前的一段时间。我想知道渲染花费了多长时间(这意味着Date()渲染完成后需要检查)。我发现可以通过设置div的innerHTML,然后(在同一脚本中)调用页面上某些按钮的click方法来做到这一点。仅在完全渲染HTML之后,而不是在div的innerHTML属性设置之后,单击处理程序才会执行。我通过将单击处理程序生成的Date()值与设置div的innerHTML属性的脚本检索的Date()值进行比较来验证这一点。

希望有人觉得这有用


归档时间:

查看次数:

31097 次

最近记录:

6 年,6 月 前