我需要准确测量我的网络应用中的文字尺寸,我通过创建一个元素(带有相关的CSS类)来实现,设置其innerHTML
然后使用{{1}将其添加到容器中}。
执行此操作后,在呈现元素之前需要等待,并且可以读取其appendChild
以找出文本的宽度。
目前,我正在使用offsetWidth
等待渲染完成。
我可以收听任何回调,还是以更可靠的方式告诉我创建的元素何时被渲染?
答案 0 :(得分:35)
目前没有DOM事件表明元素已完全呈现(例如附加的CSS应用和绘制)。这可能会使一些DOM操作代码返回错误或随机结果(比如获取元素的高度)。
使用setTimeout为浏览器提供渲染的一些开销是最简单的方法。使用
setTimeout(function(){}, 0)
可能是最实际的准确,因为它将您的代码放在活动浏览器事件队列的末尾而没有任何延迟 - 换句话说,您的代码在渲染操作之后立即排队(以及当时发生的所有其他操作) )。
答案 1 :(得分:20)
接受的答案是从2014年开始,现在已经过时了。 setTimeout
可能有用,但它不是最干净的,也不一定能保证元素已添加到DOM中。
今天,您应该使用MutationObserver来检测元素何时添加到DOM。 MutationObservers现在在所有现代浏览器中得到广泛支持(Chrome 26+,Firefox 14+,IE11,Edge,Opera 15+等。
将元素添加到DOM后,您将能够检索其实际尺寸。
这是一个简单的示例,说明如何在将元素添加到DOM时使用MutationObserver
进行侦听。
为简洁起见,我使用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!
observer
事件处理程序将在document
添加或删除任何节点时触发。在处理程序中,我们会执行contains
检查以确定myElement
中是否document
。
您不需要遍历mutations
中存储的每个MutationRecord,因为您可以直接在document.contains
执行myElement
检查。
要提高效果,请将document
替换为DOM中包含myElement
的特定元素。
答案 2 :(得分:9)
This blog post Swizec Teller建议使用requestAnimationFrame
,并检查元素的size
。
function try() {
if (!$("#element").size()) {
window.requestAnimationFrame(try);
} else {
$("#element").do_some_stuff();
}
};
在实践中它只会重试一次。因为无论如何,在下一个渲染帧中,无论是60秒还是分钟,元素都将被渲染。
答案 3 :(得分:5)
MutationObserver可能是最好的方法,但这是一个可行的简单替代方案
我有一些javascript为大表构建HTML,并将div的innerHTML设置为生成的HTML。如果我在设置innerHTML后立即获取Date()
,我发现时间戳是表完全呈现之前的一段时间。我想知道渲染需要多长时间(这意味着我需要在渲染完成后检查Date()
)。我发现我可以通过设置div的innerHTML然后(在同一个脚本中)调用页面上某个按钮的click方法来完成此操作。只有在完全呈现HTML之后才会执行click处理程序,而不仅仅是在div的innerHTML属性设置之后。我通过将Click处理程序生成的Date()值与设置div的innerHTML属性的脚本检索的Date()值进行比较来验证这一点。
希望有人发现这个有用的
答案 4 :(得分:3)
就我而言,setTimeout
或 MutationObserver
之类的解决方案并不完全可行。
相反,我使用了 ResizeObserver。根据{{3}}:
如果遵循规范,实现应该调用 在绘制之前和布局之后调整事件大小。
所以基本上观察者总是在布局后触发,因此我们应该能够获得被观察元素的正确尺寸。
作为奖励,观察者已经返回元素的尺寸。因此我们甚至不需要调用像 offsetWidth
这样的东西(即使它也应该工作)
const myElement = document.createElement("div");
myElement.textContent = "test string";
const resizeObserver = new ResizeObserver(entries => {
const lastEntry = entries.pop();
// alternatively use contentBoxSize here
const width = lastEntry.borderBoxSize.inlineSize;
const height = lastEntry.borderBoxSize.blockSize;
resizeObserver.disconnect();
console.log("width:", width, "height:", height);
});
resizeObserver.observe(myElement);
document.body.append(myElement);
我们也可以用这样一个方便的异步函数包装:
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 ...
});
答案 5 :(得分:0)
当您举例时
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
我在这做什么?
我克隆已经渲染的元素并更改要渲染的html。
接下来,我将该文本附加到容器中。
$('#container_id').append(newForm);
当我想在newForm中的按钮添加事件处理程序, WELL 时,问题就出现了,只需使用准备事件。
$(clonedForm).ready(function(event){
addEventHandlerToFormButton();
})
我希望这对你有所帮助。
PS:对不起我的英文。
答案 6 :(得分:0)
假设您的元素具有类名class =“ test” 以下功能继续测试是否已发生更改 如果有,请运行功能
number
答案 7 :(得分:0)
根据@Elliot B.的回答,我制定了适合自己的计划。
const callback = () => {
const el = document.querySelector('#a');
if (el) {
observer.disconnect();
el.addEventListener('click', () => {});
}
};
const observer = new MutationObserver(callback);
observer.observe(document.body, { subtree: true, childList: true });