繁体   English   中英

当元素快速调整大小时,JavaScript的offsetWidth和offsetHeight给出错误的值

[英]JavaScript's offsetWidth and offsetHeight give wrong value when element is resizing quickly

我正在使用香草javascript创建自己的滚动条组件。 该元素是可调整大小的,因此在调整其大小时,滚动条的最大滚动位置和大小将随之变化。

如果我以正常速度调整大小,一切都很好,但是如果我快速测试,计算结果(大小和最大位置)会产生错误的结果,我猜是因为offsetWidthoffsetHeight错误。

我的滚动条的渲染功能在调整大小时触发,sbv表示滚动条为垂直,sbh表示滚动条为水平

this.sbv.size = this.content.offsetHeight / this.content.scrollHeight;
this.sbv.style.height = (this.sbv.size * 100) + "%";
this.sbv.max = (100 - this.sbv.size * 100) / 100 * this.content.offsetHeight;
this.sbv.pos = this.content.scrollTop / this.content.scrollHeight * this.content.offsetHeight;
this.sbv.style.top = (this.sbv.pos / this.content.offsetHeight * 100) + "%";

this.sbh.size = this.content.offsetWidth / this.content.scrollWidth;
this.sbh.style.width = (this.sbh.size * 100) + "%";
this.sbh.max = (100 - this.sbh.size * 100) / 100 * this.content.offsetWidth;
this.sbh.pos = this.content.scrollLeft / this.content.scrollWidth * this.content.offsetWidth;
this.sbh.style.left = (this.sbh.pos / this.content.offsetWidth * 100) + "%";

有人知道为什么会这样吗? TIA

那只是一个理论上的答案,因为我没有花时间来设置一个repro案例,并且因为“ 产生错误的结果 ”的描述有点宽泛。


我怀疑问题实际上与您的主张相反: offsetWidthoffsetHeightscrollHeightscrollWidth实际上给您正确的值,这意味着您可能没有想到。

为了返回正确的值,这些属性的确触发了文档中元素的所有边界框的重新计算,这称为“重排”
此重排意味着您先前设置的所有CSS规则现在都已应用并处于活动状态。

所以在您的代码中,当您执行

elem.size = content.offsetHeight / content.scrollHeight;
elem.style.height = (elem.size * 100) + "%";
elem.max = (100 - elem.size * 100) / 100 * content.offsetHeight;

第一行中content.offsetHeight的值与第三行中的content.offsetHeight的值可能不再相同。

 var elem = document.getElementById('elem'); var content = document.getElementById('content'); console.log('before', content.offsetHeight); elem.size = content.offsetHeight / content.scrollHeight; elem.style.height = (elem.size * 100) + "%"; elem.max = (100 - elem.size * 100) / 100 * content.offsetHeight; console.log('after', content.offsetHeight); 
 body{ height: 100vh; } #content,#elem { border: 1px solid; } #elem { height: 800px; } 
 <div id="content"> <div id="elem"></div> </div> 

因此,不仅触发这样的多次重排对于性能来说是可怕的,而且您的计算确实可能会出错。

最好的办法是在传递变量之前先缓存所有当前值,进行所有计算,最后才设置所有新样式。

还要注意,所有这些都最好在requestAnimationFrame去抖动器中运行,因此每个绘画帧仅发生一次。

暂无
暂无

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

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