![](/img/trans.png)
[英]offsetHeight, clientHeight and scrollHeight or offsetWidth, clientWidth and scrollWidth return wrong value for Mackbook retina display
[英]JavaScript's offsetWidth and offsetHeight give wrong value when element is resizing quickly
我正在使用香草javascript创建自己的滚动条组件。 该元素是可调整大小的,因此在调整其大小时,滚动条的最大滚动位置和大小将随之变化。
如果我以正常速度调整大小,一切都很好,但是如果我快速测试,计算结果(大小和最大位置)会产生错误的结果,我猜是因为offsetWidth
或offsetHeight
错误。
我的滚动条的渲染功能在调整大小时触发,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案例,并且因为“ 产生错误的结果 ”的描述有点宽泛。
我怀疑问题实际上与您的主张相反: offsetWidth
, offsetHeight
, scrollHeight
和scrollWidth
实际上给您正确的值,这意味着您可能没有想到。
为了返回正确的值,这些属性的确触发了文档中元素的所有边界框的重新计算,这称为“重排” 。
此重排意味着您先前设置的所有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.