使用内联 offsetparent 获取元素左/顶部的实际偏移量

发布于 2024-10-26 18:03:03 字数 1439 浏览 4 评论 0原文

我正在尝试获取页面上元素的坐标。我一直在使用标准方法来获取它:

var el = element, pos = {x: 0, y: 0};
while ( el ) {
    pos.x += el.offsetLeft;
    pos.y += el.offsetTop;
    el = el.offsetParent;
}

但是当相关元素具有 display: block 并且 offsetParents 之一具有 display: inline; 时,此方法会失败。这是由于此线程中描述的事实:

< img src="https://i.sstatic.net/MJyK0.png" alt="元素从文本中间开始">

经过一些 jQuery 尝试后发现他们的 .offset()< /code>-method 返回正确的偏移量,我查看了源代码,但没有找到他们到底是如何做到的。所以我的问题是:如何获得准确的位置?我无法在这个项目中使用 jQuery,并且 线程中的方法前面描述的很麻烦,添加元素和测试工作量太大(性能角度),并且使用 Element.getBoundingClientRect 也不可用。

如果您想尝试一下,可以访问 Apple.com 打开您选择的调试器并输入以下内容

var el, el2;
el = el2 = document.querySelector('#worldwide span');
var pos = {x: 0, y: 0};
while ( el2 ) {
    pos.x += el2.offsetLeft;
    pos.y += el2.offsetTop;
    el2 = el2.offsetParent;
}
alert("Calculated position: " + pos.x + "x" + pos.y + " window size: " + screen.width + "x" + screen.height);

:我得到的代码是: 计算的位置:1354x988 窗口大小:1280x800 (即左侧的偏移量是屏幕的方式,但显然不是)

这怎么可能?有什么解决办法吗?近似值?不一定要精确,但必须比以前更好。谢谢。

编辑:这是针对 WebKit 渲染引擎的,需要澄清。

I'm trying to get the coordinates of an element on a page. I've been using the standard way to obtain it:

var el = element, pos = {x: 0, y: 0};
while ( el ) {
    pos.x += el.offsetLeft;
    pos.y += el.offsetTop;
    el = el.offsetParent;
}

But this method fails when the element in question has display: block, and one of the offsetParents has display: inline;. This is due to the fact described in this thread:

The element starts in the middle of the text

After some trying with jQuery it turns out that their .offset()-method returns the correct offset, and I've looked through the source but not found exactly how they do it. So my question is: how do I get the exact position? I can't use jQuery for this project, and the method in the thread described earlier is to cumbersome, adding an element and testing is too much work (performance perspective), and using Element.getBoundingClientRect is not available either.

If you feel like trying it out you can go to Apple.com open your debugger of choice and type in the following:

var el, el2;
el = el2 = document.querySelector('#worldwide span');
var pos = {x: 0, y: 0};
while ( el2 ) {
    pos.x += el2.offsetLeft;
    pos.y += el2.offsetTop;
    el2 = el2.offsetParent;
}
alert("Calculated position: " + pos.x + "x" + pos.y + " window size: " + screen.width + "x" + screen.height);

With this code I get: Calculated position: 1354x988 window size: 1280x800 (ie. the offset left is way of the screen, which it clearly isn't)

How is this possible? Any work-around ideas? Approximations? It does not have to be exact, but it has to be better than before. Thanks.

Edit: This is for the WebKit rendering engine, to clarify.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

孤君无依 2024-11-02 18:03:04

检查 webkitConvertPointFromNodeToPage 源代码发现它使用元素渲染器对象进行计算,如果不存在这样的渲染器,则它使用具有渲染器的最近祖先。但是,当使用祖先渲染器时,它不会调整偏移量来考虑目标与其祖先原点之间的原点差异。这意味着当相对于包含渲染器给出点时,该函数可以正常工作。如果您要计算坐标的元素没有渲染器,则需要手动将偏移调整为具有渲染器的最近的祖先(使用 offsetLeft/Top)。要确切地知道哪些元素有渲染器需要更多的研究,但通常任何没有内容但影响其他节点显示的元素(例如 SPAN)都不需要渲染器。

Examination of the webkitConvertPointFromNodeToPage source code reveals that it calculates using the element renderer object, and if no such renderer exists, it uses the neareset ancestor that has a renderer. However, when an ancestor renderer is used, it doesn't adjust the offset to account for the origin diffence between the target and it's ancestor's origin. This means the function works correctly when the point is given relative to the containing renderer. If the element you're calculating coordinates for doesn't have a renderer, you need to manually adjust the offset to the nearest ancestor that does have it (using offsetLeft/Top). To know exactly which elements have renderers would require more research, but generally any element that has no content but affects the display of other nodes, such as SPAN, does not need a renderer.

流心雨 2024-11-02 18:03:04

当我在 jQuery 中使用 $.offset().left 时,我遇到了同样的问题,试图获取段落中单词的位置。

$(document).ready() 函数内使用 $.offset().left 会产生不正确的结果。

$(window).load() 函数中使用 $.offset().left 解决了我在 WebKit 中的问题。

当可能存在会影响布局的浮动图像元素或字体时,这一点尤其重要。

I had the same problem When using $.offset().left with jQuery, trying to get the position of a word within a paragraph.

Using $.offset().left inside of a $(document).ready() function yielded an incorrect result.

Using $.offset().left in a $(window).load() function solved my problem in WebKit.

This is particularly relevant where there might be floated image elements or fonts that will affect the layout.

天邊彩虹 2024-11-02 18:03:03

我最终选择了 WebKit 的 window.webkitConvertPointFromNodeToPage,但我一直遇到一个错误,它会返回完全错误的位置。进一步的调查显示,如果有问题的节点是 display: inline,那么它将返回层次结构中最后一个块元素的位置。

搜索该图像的分辨率一无所获(我发现的只是有关 webkitConvertPointFromNodeToPage 实际执行的操作和 WebKit 源代码的非常基本的信息)。

通过猜测,我发现如果元素具有 display: inline-block ,它会返回正确的位置,因此如果该元素是内联的,那么我将其更改为 inline-block ,然后计算位置。

如果有人对这个问题有更好的解决方案,我很乐意听取您的意见!

编辑:

事实证明,将显示样式更改为内联块并不总是一个好主意,因此我没有这样做,而是使用以下方法:

var offset = {x: 0, y: 0};
if ( getStyle(el, 'display') == 'inline' ) {
    offset.x = el.offsetLeft - el.parentNode.offsetLeft;
    offset.y = el.offsetTop - el.parentNode.offsetTop;
}

var point = window.webkitConvertPointFromNodeToPage(el, new WebKitPoint(0, 0));

return {
    x: Math.round(point.x + offset.x),
    y: Math.round(point.y + offset.y)
}

我采用内联子项的 offsetTop/Left 并减去它来自它的父级。我不太确定它对具有 display: inline 的父母如何起作用,但它在 90% 的情况下都有效。

但如果有人有更好的想法,我仍然愿意接受建议。

I ended up going with WebKit's window.webkitConvertPointFromNodeToPage, but I kept hitting a bug where it would return a position that was totally wrong. Further investigation revealed that if the node in question was display: inline, then it would return the position of the last block element in the hierarchy.

Searching for a resolution for this image turned up nothing (all I found was very basic information on what webkitConvertPointFromNodeToPage actually did and WebKit's sourcecode).

By guessing I found out that it returned the correct position if the element had display: inline-block, so if the element was inline then I changed it to inline-block and then calculated the position.

If anyone has a better solution for this problem I would love to hear from you!

Edit:

Turns out changing display style to inline-block is not always a good idea, so instead of doing that I'm using this method:

var offset = {x: 0, y: 0};
if ( getStyle(el, 'display') == 'inline' ) {
    offset.x = el.offsetLeft - el.parentNode.offsetLeft;
    offset.y = el.offsetTop - el.parentNode.offsetTop;
}

var point = window.webkitConvertPointFromNodeToPage(el, new WebKitPoint(0, 0));

return {
    x: Math.round(point.x + offset.x),
    y: Math.round(point.y + offset.y)
}

I'm taking the inline child's offsetTop/Left and subtracting that from it's parent. I'm not really sure how it works on parents that have display: inline, but it works 90% of the time.

But if anyone has a better idea I'm still open for suggestions.

巷子口的你 2024-11-02 18:03:03

也许在这里您会找到jQuery.offset的源代码

如果您查看此处,您可以看到 offsetLeftoffsetTop 在旧的 IE 版本中工作不太正确。

我知道了解如何实现这个或其他事情是很有趣的。如何查看jQuery.offset函数的源代码并不那么容易。如果您希望您的代码正确工作并且独立于浏览器,您最好只使用 jQuery.offset 而不是编写自己的实现。

Probably here you will find the description of the ideas used in the source code of jQuery.offset.

If you look here you can see that offsetLeft and offsetTop works not quite correct in the old IE versions.

I understand that it's interesting to understand how this or other things can be implemented. How you see the source code of jQuery.offset function is not so easy. If you want that your code works correct and be browser independent you should better just use jQuery.offset instead of writing his own implementation it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文