【问题标题】:JavaScript getBoundingClientRect() changes while scrollingJavaScript getBoundingClientRect() 在滚动时发生变化
【发布时间】:2014-10-27 02:39:46
【问题描述】:

我想要一个元素的 Y 坐标与 Y 值 = 0 之间的确切距离,我认为它是文档的顶部。

myElement.getBoundingClientRect().top;

但 getBoundingClientRect() 的值似乎在滚动时发生了变化。如何获取 myElement 和 Y 坐标=0(文档顶部)之间的实际距离?

【问题讨论】:

  • 我可能会因为 This question 的欺骗而关闭,但你为什么使用 getBoundingClientRect 而不是任何通常的方法来获取相对于文档的偏移位置?
  • @adeneo 还有哪些其他方式?
  • 看上面的问题,或者看看jQuery在offset做了什么
  • 对于文本节点,这是唯一的解决方案,因为offset() 不可用。

标签: javascript webapi getboundingclientrect


【解决方案1】:

这是因为getBoundingClientRect() 获取与window(仅页面的当前可见部分)相关的值,而不是document(整个页面)。
因此,它在计算其值时也会考虑滚动
基本上,document = window + scroll

因此,要获得 myElement 和 Y 坐标 = 0(文档顶部)之间的距离,您还需要添加 vertical-scroll 的值:

myElement.getBoundingClientRect().top + window.scrollY;

来源:https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect

【讨论】:

  • 您的解决方案在 Android Chrome 43 上已损坏,而且我认为如果在 Internet Explorer 上使用捏合缩放功能会损坏(我的解决方案是很久以前解决的,以按照您的方式解决问题)。跨度>
【解决方案2】:

getBoundingClientRect 需要更加小心以避免scrollY/pageYOffset 中的错误:

function absolutePosition(el) {
    var
        found,
        left = 0,
        top = 0,
        width = 0,
        height = 0,
        offsetBase = absolutePosition.offsetBase;
    if (!offsetBase && document.body) {
        offsetBase = absolutePosition.offsetBase = document.createElement('div');
        offsetBase.style.cssText = 'position:absolute;left:0;top:0';
        document.body.appendChild(offsetBase);
    }
    if (el && el.ownerDocument === document && 'getBoundingClientRect' in el && offsetBase) {
        var boundingRect = el.getBoundingClientRect();
        var baseRect = offsetBase.getBoundingClientRect();
        found = true;
        left = boundingRect.left - baseRect.left;
        top = boundingRect.top - baseRect.top;
        width = boundingRect.right - boundingRect.left;
        height = boundingRect.bottom - boundingRect.top;
    }
    return {
        found: found,
        left: left,
        top: top,
        width: width,
        height: height,
        right: left + width,
        bottom: top + height
    };
}

要避免的错误是:

  • 在 Android Chrome 中滚动,因为 Chrome Mobile 43 有 wrong values 用于 scrollY/pageYOffset(尤其是当键盘显示并且您滚动时)。

  • Microsoft IE 或 Edge 中的双指缩放会导致 wrong values 用于 scrollY/pageYOffset。

  • 一些(过时的)浏览器没有高度/宽度,例如IE8

编辑:上面的代码可以通过使用document.body.getBoundingClientRect()而不是添加一个div来简化很多——虽然我还没有尝试过,所以我保留我的答案。身体也需要margin:0(reset.css 通常这样做)。 This answer 大大简化了代码,同时仍然避免了 jQuery.offset() 中的错误!

编辑 2:Chrome 61 introduced window.visualViewport 为实际视口提供正确的值,这可能是解决问题的另一种方法;但请注意,如果勾选了Settings -> Accessability -> Force enable zoom,Android Chrome 66 仍然存在错误(方向更改、焦点输入、绝对定位的弹出窗口比视口更宽的错误)。

【讨论】:

  • 完美答案。就我而言, document.body.getBoundingClientRect() 返回了错误的值,但这个答案有效。
  • 这是什么? offsetBase = absolutePosition.offsetBase; absolutePosition 没有在那里定义...
  • @Guntram absolutePosition 已定义——它是第一行的函数(函数对象)的名称。这是一种在不添加另一个全局标识符的情况下存储全局变量的“javascripty”方式。我承认它不应该通过代码审查,并且代码假定 absolutePosition 函数是在全局级别定义的。我的编辑建议您使用 document.body 作为更整洁的解决方案(尽管假定 上的边距设置为零)。另请参阅 jQuery $(),它是一个具有成员属性和成员函数的函数。
猜你喜欢
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多