javascript 如何判断动态创建的元素何时呈现
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15875128/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to tell when a dynamically created element has rendered
提问by funkybro
I need to accurately measure the dimensions of text within my web app, which I am achieving by creating an element (with relevant CSS classes), setting its innerHTML
then adding it to the container using appendChild
.
我需要准确测量 Web 应用程序中文本的尺寸,这是通过创建一个元素(具有相关的 CSS 类)、设置它innerHTML
然后使用appendChild
.
After doing this, there is a wait before the element has been rendered and its offsetWidth
can be read to find out how wide the text is.
这样做之后,在元素被渲染之前有一个等待,它offsetWidth
可以被读取以找出文本的宽度。
Currently, I'm using setTimeout(processText, 100)
to wait until the render is complete.
目前,我正在setTimeout(processText, 100)
等待渲染完成。
Is there any callback I can listen to, or a more reliable way of telling when an element I have created has been rendered?
有没有我可以听到的回调,或者有更可靠的方式来告诉我创建的元素何时被渲染?
采纳答案by mystrdat
There is currently no DOM event indicating that an element has been fully rendered (eg. attached CSS applied and drawn). This can make some DOM manipulation code return wrong or random results (like getting the height of an element).
目前没有 DOM 事件表明一个元素已经完全呈现(例如,附加的 CSS 应用和绘制)。这可能会使某些 DOM 操作代码返回错误或随机的结果(例如获取元素的高度)。
Using setTimeout to give the browser some overhead for rendering is the simplest way. Using
使用 setTimeout 为浏览器提供一些渲染开销是最简单的方法。使用
setTimeout(function(){}, 0)
is perhaps the most practically accurate, as it puts your code at the end of the active browser event queue without any more delay - in other words your code is queued right after the render operation (and all other operations happening at the time).
可能是最实际的准确方法,因为它会将您的代码放在活动浏览器事件队列的末尾而不会再有任何延迟 - 换句话说,您的代码在渲染操作(以及当时发生的所有其他操作)之后立即排队。
回答by Elliot B.
The accepted answer is from 2014 and is now outdated. A setTimeout
may work, but it's not the cleanest and it doesn't necessarily guarantee that the element has been added to the DOM.
接受的答案是从 2014 年开始的,现在已经过时了。AsetTimeout
可能有效,但它不是最干净的,并且不一定保证该元素已添加到 DOM 中。
Today, a MutationObserveris what you should use to detect when an element has been added to the DOM.MutationObservers are now widely supported across all modern browsers (Chrome 26+, Firefox 14+, IE11, Edge, Opera 15+, etc).
今天,你应该使用MutationObserver来检测元素何时被添加到 DOM。MutationObservers 现在在所有现代浏览器(Chrome 26+、Firefox 14+、IE11、Edge、Opera 15+ 等)中得到广泛支持。
When an element has been added to the DOM, you will be able to retrieve its actual dimensions.
将元素添加到 DOM 后,您将能够检索其实际尺寸。
Here's a simple example of how you can use a MutationObserver
to listen for when an element is added to the DOM.
这是一个简单的示例,说明如何使用 aMutationObserver
来侦听何时将元素添加到 DOM。
For brevity, I'm using jQuery syntax to build the node and insert it into the DOM.
为简洁起见,我使用 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!
The observer
event handler will trigger whenever any node is added or removed from the document
. Inside the handler, we then perform a contains
check to determine if myElement
is now in the document
.
的observer
事件处理程序将触发每当任何节点被添加或从去除document
。在处理程序内部,我们然后执行contains
检查以确定myElement
现在是否在document
.
You don't need to iterate over each MutationRecord stored in mutations
because you can perform the document.contains
check directly upon myElement
.
您不需要遍历存储在的每个 MutationRecord,mutations
因为您可以document.contains
直接对myElement
.
To improve performance, replace document
with the specific element that will contain myElement
in the DOM.
要提高性能,请替换为 DOMdocument
中将包含的特定元素myElement
。
回答by Yuval A.
This blog postBy Swizec Teller, suggests using requestAnimationFrame
, and checking for the size
of the element.
Swizec Teller 撰写的这篇博文建议使用requestAnimationFrame
,并检查size
元素的 。
function try() {
if (!$("#element").size()) {
window.requestAnimationFrame(try);
} else {
$("#element").do_some_stuff();
}
};
in practice it only ever retries once. Because no matter what, by the next render frame, whether it comes in a 60th of a second, or a minute, the element will have been rendered.
实际上它只重试一次。因为无论如何,到下一个渲染帧,无论是在 60 分之一秒还是一分钟内,元素都将被渲染。
回答by hanksterr7
The MutationObserver is probably the best approach, but here's a simple alternative that may work
MutationObserver 可能是最好的方法,但这里有一个简单的替代方法可能会起作用
I had some javascript that built the HTML for a large table and set the innerHTML of a div to the generated HTML. If I fetched Date()
immediately after setting the innerHTML, I found that the timestamp was for a time prior to the table being completely rendered. I wanted to know how long the rendering was taking (meaning I needed to check Date()
after the rendering was done). I found I could do this by setting the innerHTML of the div and then (in the same script) calling the click method of some button on the page. The click handler would get executed only after the HTML was fully rendered, not just after the innerHTML property of div got set. I verified this by comparing the Date() value generated by the click handler to the Date() value retrieved by the script that was setting the innerHTML property of the div.
我有一些 javascript 为一个大表构建了 HTML,并将 div 的 innerHTML 设置为生成的 HTML。如果我Date()
在设置innerHTML 后立即获取,我发现时间戳是在表格完全呈现之前的一段时间。我想知道渲染需要多长时间(这意味着我需要Date()
在渲染完成后进行检查)。我发现我可以通过设置 div 的 innerHTML 然后(在同一个脚本中)调用页面上某个按钮的 click 方法来做到这一点。只有在 HTML 完全呈现后才会执行单击处理程序,而不仅仅是在 div 的 innerHTML 属性设置之后。我通过将单击处理程序生成的 Date() 值与设置 div 的 innerHTML 属性的脚本检索到的 Date() 值进行比较来验证这一点。
Hope someone finds this useful
希望有人觉得这很有用
回答by relaxslow
suppose your element has classname class="test" The following function continue test if change has occured if it does, run the function
假设您的元素具有类名 class="test" 下面的函数继续测试是否发生了变化,如果发生变化,则运行该函数
function addResizeListener(elem, fun) {
let id;
let style = getComputedStyle(elem);
let wid = style.width;
let hei = style.height;
id = requestAnimationFrame(test)
function test() {
let newStyle = getComputedStyle(elem);
if (wid !== newStyle.width ||
hei !== newStyle.height) {
fun();
wid = newStyle.width;
hei = newStyle.height;
}
id = requestAnimationFrame(test);
}
}
let test = document.querySelector('.test');
addResizeListener(test,function () {
console.log("I changed!!")
});
回答by Nazareno Castro
when you make for example
当你做例如
var clonedForm = $('#empty_form_to_clone').clone(true)[0];
var newForm = $(clonedForm).html().replace(/__prefix__/g, next_index_id_form);
// next_index_id_form is just a integer
What am I doing here?
I clone a element already rendered and change the html to be rendered.
我在这是要干嘛?
我克隆了一个已经呈现的元素并更改了要呈现的 html。
Next i append that text to a container.
接下来我将该文本附加到一个容器中。
$('#container_id').append(newForm);
The problem comes when i want to add a event handler to a button inside newForm, WELL, just use readyevent.
当我想将事件处理程序添加到 newForm 中的按钮时,问题就出现了,WELL,只需使用ready事件。
$(clonedForm).ready(function(event){
addEventHandlerToFormButton();
})
I hope this help you.
我希望这对你有帮助。
PS: Sorry for my English.
PS:对不起我的英语。