【问题标题】:JavaScript's offsetWidth and offsetHeight give wrong value when element is resizing quickly当元素快速调整大小时,JavaScript offsetWidth 和 offsetHeight 给出错误值
【发布时间】:2019-03-28 12:43:59
【问题描述】:

我正在使用 vanilla 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) + "%";

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

【问题讨论】:

  • 你应该去抖动这些事件。
  • 我使用了setTimeoutrequestAnimationFrame,但仍然无法正常工作。

标签: javascript html css


【解决方案1】:

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


我怀疑问题实际上与您的说法相反: 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 的值和第三行的值可能不再相同。

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 debouncer 中运行,因此每个绘画帧只发生一次。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-08
    • 2017-05-31
    • 2017-03-14
    • 2014-03-29
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    相关资源
    最近更新 更多