getBoundingClientRect()在XUL中返回零

18

我有一个关于我的 Firefox 扩展的问题。

我有一个 XUL 弹出面板,其中包含一个用于显示标签云的 hbox 和一个用于向此 hbox 添加 div 的 JS 代码:

<hbox id="tag_base" ondblclick="alert('done')"/>

JS:

var root = document.getElementById('tag_base');
var tag = document.createElement('div');
tag.textContent = 'test';
root.appendChild(tag);
var rect = tag.getBoundingClientRect()
alert(rect.top)
我需要获取每个添加的div的尺寸,然而getBoundingClientRect无法正常工作。 如果我删除警告,它总是返回零。 加上警告就不一样了: 第一次调用警告时,尽管div出现在屏幕上,但返回零。 任何后续警告都会返回正确的坐标。
如果我在Chromebug中设置断点,所有内容都会正确报告。 如果我不以任何方式打断执行,并运行循环,只有零被返回。
这让我感到非常困惑。 调用"boxObject"会产生相同的结果,而"getClientRects[0]"在第一次调用时未定义。
任何可能导致此问题的提示将不胜感激。

请查看Neil在评论中的回答。(不确定您是否会收到SO上答案评论的通知。) - Nickolay
3个回答

55
注意:如果你使用 getBoundingClientRect() 方法获取一个 display:none 元素的位置信息,它会在 html 文档中返回 0。

4
旧帖子,但这正是我的问题所在。 - Jay
3
救了我的一天!谢谢你! - sudoremo
2
非常感谢!我正在使用 getBoundingClientRect 与 Bootstrap 的模态框,但是所有的值都是0。然后我再次尝试了 shown.bs.modal,这应该可以解决问题。再次感谢! - user9235753
仍然在帮助人们,已经快8年了。谢谢!我有一个函数,用于在屏幕上时动画元素,其中使用了这个函数,但我刚刚意识到它今天停止工作了。原来是因为几周前我给整个body添加了“display:none”,持续了1秒钟。 - Chris Rahmé
1
谢谢!我在一个滚动函数中使用了 getBoundingClientRect。只有指向我的 <a id="top"></a> 标签的“回到顶部”链接无法正常工作。原因是该标签被设置为 display: none;。将其更改为 visibility: hidden; 即可解决问题。 - RemBem

10
尽管我找不到关于这个看似基本问题的任何文档,但你注意到的问题很可能是因为在你请求坐标时布局(也称为“回流”)过程尚未运行。
布局/回流过程使用页面的DOM和页面上的任何样式确定元素和页面其他部分的位置和尺寸(你可以尝试阅读HTML回流笔记,尽管它并不针对Web开发人员,而且可能有点过时)。
这个回流过程不会在DOM的任何更改后同步运行,否则像以下代码的执行就会出现问题。
elt.style.top = "5px";
elt.style.left = "15px";

会更新两次布局,效率低下。

另一方面,通过.offsetTop请求元素位置/尺寸应该强制布局返回正确的信息。由于某种原因,在您的情况下并没有发生这种情况,我不确定是为什么。

请创建一个简单的测试用例来演示问题,并在bugzilla.mozilla.org上提交错误报告(抄送我 - ***********@gmail.com)。

我猜想这与XUL布局有关,它比HTML不够健壮;您可以尝试在iframe中创建云,或者至少使用createElementNS创建真正的HTML元素而不是使用当前代码创建的xul:div


非常感谢您的详细回复,我会按照您建议的方式在Bugzilla上提交一个测试用例。谢谢! - Andrei Sch.
2
这可能是因为弹出窗口在第一次显示之前不会进行布局,除了菜单列表的情况,因为弹出窗口必须进行布局,以便列表可以根据其大小调整。 - Neil

7

确保DOM已经准备就绪。在我的情况下,即使是在点击事件上使用getBoundingClientRect函数时,事件的绑定也需要在DOM准备就绪后发生。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接