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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 02:25:21  来源:igfitidea点击:

How to tell when a dynamically created element has rendered

javascriptdom

提问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 innerHTMLthen 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 offsetWidthcan 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 setTimeoutmay 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 MutationObserverto 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 observerevent handler will trigger whenever any node is added or removed from the document. Inside the handler, we then perform a containscheck to determine if myElementis now in the document.

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

You don't need to iterate over each MutationRecord stored in mutationsbecause you can perform the document.containscheck directly upon myElement.

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

To improve performance, replace documentwith the specific element that will contain myElementin the DOM.

要提高性能,请替换为 DOMdocument中将包含的特定元素myElement

回答by Yuval A.

This blog postBy Swizec Teller, suggests using requestAnimationFrame, and checking for the sizeof 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:对不起我的英语。