运行此代码:
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毫秒,值是正确的。好的,设置超时将是解决问题的一个选项,但我认为必须有一个比这更优雅的解决方案。有人知道这个解决方案吗?
回到浏览器(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回调中的offsetTop
s)。
您也可以使用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>