我想知道如何在JavaScript中获取img和div等HTML元素的X和Y位置。


当前回答

更新:

递归方法(在我以前的答案中)创建了许多调用堆栈。在这种情况下,我们可以使用while循环来避免递归:

/**
 *
 * @param {HTMLElement} el
 * @return {{top: number, left: number}}
 */
function getDocumentOffsetPosition(el) {
    let top = 0, left = 0;
    while (el !== null) {
        top += el.offsetTop;
        left += el.offsetLeft;
        el = el.offsetParent;
    }
    return {top, left};
}

旧答案:

/**
 *
 * @param {HTMLElement} el
 * @return {{top: number, left: number}}
 */
function getDocumentOffsetPosition(el) {
    var position = {
        top: el.offsetTop,
        left: el.offsetLeft
    };
    if (el.offsetParent) {
        var parentPosition = getDocumentOffsetPosition(el.offsetParent);
        position.top += parentPosition.top;
        position.left += parentPosition.left;
    }
    return position;
}

感谢Thinkingtiff的回答,这只是另一个版本。

其他回答

经过大量研究和测试,这似乎奏效了

function getPosition(e) {
    var isNotFirefox = (navigator.userAgent.toLowerCase().indexOf('firefox') == -1);
    var x = 0, y = 0;
    while (e) {
        x += e.offsetLeft - e.scrollLeft + (isNotFirefox ? e.clientLeft : 0);
        y += e.offsetTop - e.scrollTop + (isNotFirefox ? e.clientTop : 0);
        e = e.offsetParent;
    }
    return { x: x + window.scrollX, y: y + window.scrollY };
}

看见http://jsbin.com/xuvovalifo/edit?html,js,输出

我成功地使用Andy E的解决方案,根据用户单击的表行中的链接来定位引导2模式。该页面是Tapestry 5页面,下面的javascript被导入到java页面类中。

javascript代码:

function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset   = elemRect.top - bodyRect.top;
offset   = offset + 20;
$('#serviceLineModal').css("top", offset);

}

我的模式代码:

<div id="serviceLineModal" class="modal hide fade add-absolute-position" data-backdrop="static" 
 tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="top:50%;">
<div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
    <h3 id="myModalLabel">Modal header</h3>
</div>

<div class="modal-body">
    <t:zone t:id="modalZone" id="modalZone">
        <p>You selected service line number: ${serviceLineNumberSelected}</p>
    </t:zone>
</div>

<div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <!-- <button class="btn btn-primary">Save changes</button> -->
</div>

循环中的链接:

<t:loop source="servicesToDisplay" value="service" encoder="encoder">
<tr style="border-right: 1px solid black;">       
    <td style="white-space:nowrap;" class="add-padding-left-and-right no-border"> 
        <a t:type="eventLink" t:event="serviceLineNumberSelected" t:context="service.serviceLineNumber" 
            t:zone="pageZone" t:clientId="modalLink${service.serviceLineNumber}"
            onmouseover="setLinkPosition(this);">
            <i class="icon-chevron-down"></i> <!-- ${service.serviceLineNumber} -->
        </a>
    </td>

页面类中的java代码:

void onServiceLineNumberSelected(String number){
    checkForNullSession();
    serviceLineNumberSelected = number;
    addOpenServiceLineDialogCommand();
    ajaxResponseRenderer.addRender(modalZone);
}

protected void addOpenServiceLineDialogCommand() {
    ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
        @Override
        public void run(JavaScriptSupport javascriptSupport) {
            javascriptSupport.addScript("$('#serviceLineModal').modal('show');");
        }
    });
}

希望这对某人有所帮助,这篇文章帮了大忙。

虽然这很可能会在这么多答案的底部丢失,但这里的顶级解决方案并不适合我。据我所知,其他答案都没有帮助。情况:在HTML5页面中,我有一个菜单,它是页眉中的导航元素(不是页眉,而是另一个元素中的页眉)。我希望一旦用户滚动到顶部,导航就一直保持在顶部,但在此之前,标题是绝对定位的(所以我可以让它稍微覆盖一些其他内容)。上述解决方案从未触发过更改,因为.offsetTop不会更改,因为这是一个绝对定位的元素。此外,scrollTop属性只是最顶部元素的顶部。。。也就是说0并且总是0。我使用这两个(以及getBoundingClientRect结果)执行的任何测试都不会告诉我导航栏的顶部是否曾滚动到可查看页面的顶部(再次,正如控制台中所报告的那样,它们只是在滚动时保持相同的数字)。

解决方案我使用的解决方案

window.visualViewport.pageTop

pageTop属性的值反映了屏幕的可视部分,因此允许我跟踪元素相对于可视区域边界的位置。

也许没必要说,每当我处理滚动时,我都希望使用这个解决方案以编程方式响应正在滚动的元素的移动。希望它能帮助其他人。重要提示:这似乎在Chrome和Opera中有效,在Firefox(6-2018)中肯定不行。。。在Firefox支持visualViewport之前,我建议不要使用这种方法(我希望他们很快会使用……这比其他方法更有意义)。更新:请注意此解决方案。虽然我仍然发现我发现的对于“……以编程方式响应滚动元素的移动”的情况非常有用。我遇到的问题的更好解决方案是使用CSS在元素上设置位置:粘滞。使用sticky,您可以在不使用javascript的情况下让一个元素保持在顶部(注意:有时这不会像将元素更改为固定的那样有效,但对于大多数情况,sticky方法可能会更好)更新01:所以我意识到,对于不同的页面,我需要在一个稍微复杂的滚动设置中检测元素的位置(视差加上作为消息一部分滚动经过的元素)。在这种情况下,我意识到以下内容提供了我用来确定何时做某事的价值:

  let bodyElement = document.getElementsByTagName('body')[0];
  let elementToTrack = bodyElement.querySelector('.trackme');
  trackedObjPos = elementToTrack.getBoundingClientRect().top;
  if(trackedObjPos > 264)
  {
    bodyElement.style.cssText = '';
  }

希望这个答案现在更有用。

这是一个使用vanilla JS递归迭代element.offsetTop和element.ooffsetParent的现代1行代码:

功能:

getTop = el => el.offsetTop + (el.offsetParent && getTop(el.offsetParent))

用法:

const el = document.querySelector('#div_id');
const elTop = getTop(el)

优势:

无论当前滚动位置如何,始终返回绝对垂直偏移。


传统语法:

function getTop(el) {
  return el.offsetTop + (el.offsetParent && getTop(el.offsetParent));
}

我接受了@meouw的回答,添加到允许边界的clientLeft中,然后创建了三个版本:

getAbsoluteOffsetFromBody-类似于@meouw,它获取相对于文档的body或html元素的绝对位置(取决于quicks模式)

getAbsoluteOffsetFromGivenElement-返回相对于给定元素的绝对位置(relativeEl)。注意,给定的元素必须包含元素el,否则其行为将与getAbsoluteOffsetFromBody相同。如果在另一个(已知)元素中包含两个元素(可选地,节点树上的多个节点),并且希望使它们处于相同的位置,则这非常有用。

getAbsoluteOffsetFromRelative-返回相对于具有position:relative的第一个父元素的绝对位置。这与getAbsoluteOffsetFromGivenElement类似,原因相同,但仅限于第一个匹配元素。

getAbsoluteOffsetFromBody = function( el )
{   // finds the offset of el from the body or html element
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromGivenElement = function( el, relativeEl )
{   // finds the offset of el from relativeEl
    var _x = 0;
    var _y = 0;
    while( el && el != relativeEl && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromRelative = function( el )
{   // finds the offset of el from the first parent with position: relative
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
        if (el != null)
        {
            if (getComputedStyle !== 'undefined')
                valString = getComputedStyle(el, null).getPropertyValue('position');
            else
                valString = el.currentStyle['position'];
            if (valString === "relative")
                el = null;
        }
    }
    return { top: _y, left: _x };
}

如果您仍然有问题,特别是与滚动有关的问题,您可以尝试查看http://www.greywyvern.com/?post=331-我注意到getStyle中至少有一段有问题的代码,假设浏览器运行正常,这段代码应该是不错的,但根本没有测试其他代码。