获取元素相对于父容器的位置/偏移量?

Posted

技术标签:

【中文标题】获取元素相对于父容器的位置/偏移量?【英文标题】:Get position/offset of element relative to a parent container? 【发布时间】:2012-07-23 00:02:15 【问题描述】:

我习惯于使用 jQuery。然而,在我当前的项目中,我使用 zepto.js。 Zepto 不像 jQuery 那样提供position() 方法。 Zepto 仅附带offset()

知道如何使用纯 js 或 Zepto 检索容器相对于父级的偏移量吗?

【问题讨论】:

@Supersharp 在使用纯 javascript 时使用 JavaScript 标签。如果您使用的是框架或库,那么您 使用JavaScript 标记。如果你的名字是杰夫,我不会叫你莎莉。 @John 这是一种意见,但它不是 SO 的工作方式。请阅读 javascript 标签指南。在这种情况下,它应该与库标签一起使用。 【参考方案1】:

示例

所以,如果我们有一个 id 为“child-element”的子元素,并且我们想获得它相对于父元素的左/上位置,比如一个具有“item-parent”类的 div,我们会使用这段代码。

var position = $("#child-element").offsetRelative("div.item-parent");
alert('left: '+position.left+', top: '+position.top);

插件最后,对于实际的插件(带有一些说明发生了什么的注释):

// offsetRelative (or, if you prefer, positionRelative)
(function($)
    $.fn.offsetRelative = function(top)
        var $this = $(this);
        var $parent = $this.offsetParent();
        var offset = $this.position();
        if(!top) return offset; // Didn't pass a 'top' element 
        else if($parent.get(0).tagName == "BODY") return offset; // Reached top of document
        else if($(top,$parent).length) return offset; // Parent element contains the 'top' element we want the offset to be relative to 
        else if($parent[0] == $(top)[0]) return offset; // Reached the 'top' element we want the offset to be relative to 
        else  // Get parent's relative offset
            var parent_offset = $parent.offsetRelative(top);
            offset.top += parent_offset.top;
            offset.left += parent_offset.left;
            return offset;
        
    ;

    $.fn.positionRelative = function(top)
        return $(this).offsetRelative(top);
    ;
(jQuery));

注意:您可以在 mouseClick 或 mouseover 事件中使用 this

$(this).offsetRelative("div.item-parent");

【讨论】:

我没有看到滚动。可能会发生很多奇怪的情况。 jquery.min.js:2 Uncaught RangeError: Maximum call stack size exceeded 这是它抛出的错误【参考方案2】:

我在 Internet Explorer 中是这样做的。

function getWindowRelativeOffset(parentWindow, elem) 
    var offset = 
        left : 0,
        top : 0
    ;

    // relative to the target field's document
    offset.left = elem.getBoundingClientRect().left;
    offset.top = elem.getBoundingClientRect().top;

    // now we will calculate according to the current document, this current
    // document might be same as the document of target field or it may be
    // parent of the document of the target field
    var childWindow = elem.document.frames.window;
    while (childWindow != parentWindow) 
        offset.left = offset.left + childWindow.frameElement.getBoundingClientRect().left;
        offset.top = offset.top + childWindow.frameElement.getBoundingClientRect().top;
        childWindow = childWindow.parent;
    

    return offset;
;

=================== 你可以这样称呼它

getWindowRelativeOffset(top, inputElement);

我只关注 IE,但其他浏览器也可以做类似的事情。

【讨论】:

【参考方案3】:

警告:jQuery,不是标准的 JavaScript

element.offsetLeftelement.offsetTop 是纯 JavaScript 属性,用于查找元素相对于其 offsetParent 的位置;是最近的父元素,位置为relativeabsolute

或者,您始终可以使用Zepto 来获取元素及其父元素的位置,然后将两者相减:

var childPos = obj.offset();
var parentPos = obj.parent().offset();
var childOffset = 
    top: childPos.top - parentPos.top,
    left: childPos.left - parentPos.left

这有利于为您提供子代相对于其父代的偏移量,即使父代未定位。

【讨论】:

元素的定位 static 不是偏移父级。 不要在大括号内使用分号,使用逗号 固定位置怎么样?他们抵消了父母吗? 是的,@Ayya-position fixed 也会创建一个新的偏移上下文 @vsync 自从 2016 年 1 月 ie9 达到 EOL 以来,jQuery 并不是万能之王,我们在所有主流浏览器中都有标准化的 DOM 选择,学习纯 js。此外,关于使用什么框架的意见在 SO 上也没有地位,因为它在很大程度上取决于项目和目标平台。【参考方案4】:

我得到了另一个解决方案。子属性值减去父属性值

$('child-div').offset().top - $('parent-div').offset().top;

【讨论】:

【参考方案5】:

在纯 js 中只需使用 offsetLeftoffsetTop 属性。 小提琴示例:http://jsfiddle.net/WKZ8P/

var elm = document.querySelector('span');
console.log(elm.offsetLeft, elm.offsetTop);
p    position:relative; left:10px; top:85px; border:1px solid blue; 
span position:relative; left:30px; top:35px; border:1px solid red; 
<p>
    <span>paragraph</span>
</p>

【讨论】:

谢谢。还有一种方法可以获得 parent.parent 元素的偏移量吗? p.offsetTop + p.parentNode.offsetTop 几年前,您可以将其包装在递归函数调用中,like PPK proposed。您可以更改函数以传递要上升的级别数或使用选择器来模仿$(selector).parents(parentSelector)。我更喜欢这个解决方案,因为 zepto 实现只适用于支持 getBoundingClientsRect 的浏览器 - 有些手机不支持。 我认为getBoundingClientsRect 得到了广泛的支持......如果有人知道哪些手机不支持它,我会很感兴趣(找不到任何关于它的手机支持表)。 这可能是最正确的答案,即使它没有被标记。我的个人解决方案是将$(this).offset().left 更改为this.offsetLeft 这也修复了 3d 转换父级内部的错误 jQuery.position() 行为,非常感谢!【参考方案6】:

使用纯 JS 确实很容易,只需这样做,也适用于固定和动画 html 5 面板,我制作并尝试了这段代码,它适用于任何浏览器(包括 IE 8):

<script type="text/javascript">
    function fGetCSSProperty(s, e) 
        try  return s.currentStyle ? s.currentStyle[e] : window.getComputedStyle(s)[e]; 
        catch (x)  return null;  
    
    function fGetOffSetParent(s) 
        var a = s.offsetParent || document.body;

        while (a && a.tagName && a != document.body && fGetCSSProperty(a, 'position') == 'static')
            a = a.offsetParent;
        return a;
    
    function GetPosition(s) 
        var b = fGetOffSetParent(s);

        return  Left: (b.offsetLeft + s.offsetLeft), Top: (b.offsetTop + s.offsetTop) ;
        
</script>

【讨论】:

您是否测试了所有可能的父节点和元素属性的情况?这是否考虑了滚动和嵌套滚动?【参考方案7】:

将事件的偏移量与父元素的偏移量相加得到事件的绝对偏移位置。

一个例子:

HTMLElement.addEventListener('mousedown',function(e)

    var offsetX = e.offsetX;
    var offsetY = e.offsetY;

    if( e.target != this ) // 'this' is our HTMLElement

        offsetX = e.target.offsetLeft + e.offsetX;
        offsetY = e.target.offsetTop + e.offsetY;

    

当事件目标不是事件注册的元素时,它会将父级的偏移量与当前事件偏移量相加,以计算“绝对”偏移值。

根据 Mozilla Web API:“HTMLElement.offsetLeft 只读属性返回当前元素左上角 在 HTMLElement 内向左偏移的像素数.offsetParent 节点。"

这主要发生在您在包含更多子项的父项上注册事件时,例如:具有内部图标或文本跨度的按钮,具有内部跨度的 li 元素。等等……

【讨论】:

父级的父级呢?有滚动条的嵌套元素呢?以前的带有 display:none 的元素呢?一个真正的文档偏移位置几乎是不可能计算出来的,但是渲染引擎可以知道它。糟糕的是,像文档位置这样的简单属性从未包含在 DOM 中。 @DavidSpector 字

以上是关于获取元素相对于父容器的位置/偏移量?的主要内容,如果未能解决你的问题,请参考以下文章

jquery 常用方法中那些我不知道的事

获取元素大小偏移量及鼠标位置

如何正确获取 DOM 元素的位置偏移量? [复制]

在没有 getBoundingClientRect 的情况下获取相对于文档的元素偏移量(Webkit 错误)

JS如何判断元素相对于父窗口的绝对位置?

如何获取android中元素相对于父元素的位置/偏移量?