简体   繁体   English

如何检查HTMLElement是否已完全加载

[英]How to check if an HTMLElement is fully loaded

Run this code: 运行此代码:

 window.onload = function () { const sections = document.querySelectorAll("section"); let eT = []; for (let i = 0, len = sections.length; i < len; i++) { const el = sections[i]; if (el.parentNode.className !== "wrapper") { const wrapper = document.createElement("div"); wrapper.className = "wrapper"; el.parentNode.appendChild(wrapper); wrapper.appendChild(el); } const elCont = document.querySelectorAll(".wrapper")[i]; eT[i] = elCont.offsetTop; setTimeout(() => { console.log(eT[i], elCont.offsetTop) }, 100); } } 
 section{ width: 100vw; height: 1000px; position: relative; border: 1px solid; } body{ position: relative; } 
 <body> <section></section> <section></section> <section></section> <section></section> </body> 

As you can see, the DOM manipulations, then reading them offsetTops happen too quick, so if i read they offsetTops immediately after creating them, adding them to the body, then adding the sections to them as childs, the values are wrong. 如您所见,DOM操作然后读取它们的offsetTops发生得太快了,因此,如果我在创建它们后立即读取它们的offsetTops,将它们添加到主体中,然后将这些部分作为孩子添加到它们中,则值是错误的。 But if i wait 100ms, the values are correct. 但是,如果我等待100毫秒,则值是正确的。 Okay, setting a timeout would be an option to solve the problem, but i think there must be a solution which is more elegant than this. 好的,设置超时将是解决问题的一种选择,但是我认为必须有一个比这更优雅的解决方案。 Someone knows this solution? 有人知道这个解决方案吗?

Yielding back to the browser ( setTimeout is one way, requestAnimationFrame is another) is indeed how you do this. 确实可以做到这一点,即返回到浏览器( setTimeout是一种方法, requestAnimationFrame是另一种方法)。 It's so that you allow the browser time to render the result, which happens sometime after the task in which you've added the elements completes (in your case, the task that ran your load event handler). 这样一来,您就可以让浏览器有时间来呈现结果,这是在添加元素的任务(在您的情况下,是运行load事件处理程序的任务)完成之后的某个时间发生的。

setTimeout with a timeout of 0 works in most cases; 在大多数情况下, setTimeout的超时值为0是有效的; I've had to use values between 60 and 100 on Firefox in the past, but test in your target environments. 过去,我不得不在Firefox上使用介于60到100之间的值,但是要在目标环境中进行测试。 You might also play around with requestAnimationFrame callbacks, which happen much sooner than 100ms (provided the browser isn't blocked on something): 您可能还需要处理requestAnimationFrame回调,该回调发生的时间比100ms要早得多(前提是浏览器未在某些事件上被阻止):

 window.onload = function () { const sections = document.querySelectorAll("section"); let eT = []; for (let i = 0, len = sections.length; i < len; i++) { const el = sections[i]; if (el.parentNode.className !== "wrapper") { const wrapper = document.createElement("div"); wrapper.className = "wrapper"; el.parentNode.appendChild(wrapper); wrapper.appendChild(el); } const elCont = document.querySelectorAll(".wrapper")[i]; eT[i] = elCont.offsetTop; requestAnimationFrame(() => { console.log(eT[i], elCont.offsetTop) }); } } 
 section{ width: 100vw; height: 1000px; position: relative; border: 1px solid; } body{ position: relative; } 
 <body> <section></section> <section></section> <section></section> <section></section> </body> 

That example works for me on Firefox, Chrome, and Edge ("works for me" => I see 0, 1002, 2004, and 3006 for the offsetTop s in the rAF callback). 该示例在Firefox,Chrome和Edge上对我有效(“对我有用” =>在rAF回调中, offsetTop代表0、1002、2004和3006)。

You could also use the MutationObserver for this, since it will get trigged after the elements have been added to the DOM (here .wrapper ). 您也可以为此使用MutationObserver ,因为在将元素添加到DOM(此处为.wrapper )之后,它将触发该.wrapper

 window.onload = function(){ const sections = document.querySelectorAll("section"); //https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver var tObserver = new MutationObserver(function(mutations){ if(mutations){ for(let i=0, len=sections.length; i<len; i++){ console.log('MutationObserver', sections[i].offsetTop) }; this.disconnect() } }); tObserver.observe(document, {attributes: false, childList: true, characterData: true, subtree: true}); let eT = []; for(let i=0, len=sections.length; i<len; i++){ const el = sections[i]; if(el.parentNode.className !== "wrapper"){ const wrapper = document.createElement("div"); wrapper.className = "wrapper"; el.parentNode.appendChild(wrapper); wrapper.appendChild(el); }; const elCont = document.querySelectorAll(".wrapper")[i]; eT[i] = elCont.offsetTop; console.log('in for loop', elCont.offsetTop); setTimeout(() => { console.log('in timeout', elCont.offsetTop) }, 100) } } 
 section{ border: 1px solid; height: 1000px; position: relative; width: 100vw } body{ position: relative } 
 <section></section> <section></section> <section></section> <section></section> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM