如何检查HTMLElement是否已满载

问题描述 投票:2回答:2

运行此代码:

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>

正如你所看到的,DOM操作,然后读取它们offsetTops发生得太快,所以如果我在创建它们之后立即读取offsetTops,将它们添加到正文,然后将这些部分作为子项添加到它们,则值是错误的。但是,如果我等待100毫秒,值是正确的。好的,设置超时将是解决问题的一个选项,但我认为必须有一个比这更优雅的解决方案。有人知道这个解决方案吗?

javascript html css
2个回答
2
投票

回到浏览器(setTimeout是单向的,requestAnimationFrame是另一种方式)确实是你如何做到这一点。这样您就可以允许浏览器时间呈现结果,这会在您添加元素的任务完成之后的某个时间发生(在您的情况下,运行load事件处理程序的任务)。

在大多数情况下,超时为0的setTimeout可以使用;我过去不得不在Firefox上使用60到100之间的值,而是在目标环境中进行测试。您也可以使用requestAnimationFrame回调,这种回调发生的时间早于100毫秒(假设浏览器未被阻止):

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>

这个例子对我来说适用于Firefox,Chrome和Edge(“适用于我”=>我看到0,1002,2004和3006用于rAF回调中的offsetTops)。


1
投票

您也可以使用MutationObserver,因为它会在元素添加到DOM(此处为.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>
© www.soinside.com 2019 - 2024. All rights reserved.