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


125

我习惯于使用jQuery。但是,在我当前的项目中,我使用zepto.js。Zepto没有提供position()像jQuery这样的方法。Zepto仅随附offset()

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


4
在询问JavaScript问题时拒绝接受jQuery答案(甚至没有标记为jQuery!)。
约翰,

@John,您注意到zepto标签了吗?
Supersharp

@Supersharp使用JavaScript纯JavaScript时使用标记。如果您使用的框架或库,那么你就不能使用JavaScript标签。如果您叫Jeff,我不会打给您Sally。
约翰,

@John是一种意见,但不是SO的工作方式。请阅读javascript标记指南。在这种情况下,它应与库标签一起使用。
超级锐利

@Supersharp是的,所以没有能力;文字标签通货膨胀。😒︎–
约翰

Answers:


188

警告:jQuery,不是标准JavaScript

element.offsetLeft并且element.offsetTop是用于查找元素相对于其位置的纯javascript属性offsetParent;是位置为relative或的最近的父元素absolute

另外,您始终可以使用Zepto来获取元素及其父元素的位置,并简单地将两者相减:

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

这样的好处是,即使未放置父级,也可以使子级相对于父级偏移。


9
元素的位置static不是偏移父级。
Esailija

5
不要在括号内使用分号,请使用逗号
Luca Borrione 2013年

1
固定位置怎么样?他们会补偿父母吗?
Ayyash 2014年

1
是的,也是固定@ Ayya-位置创建一个新的偏移方面
mmmeff

9
自2016年1月ie9进入EOL以来,@ vsync jQuery并不是什么王者,我们在所有主要浏览器中都有标准化的DOM选择,学习纯js。另外,关于使用哪种框架的观点在SO上也没有地位,因为它很大程度上取决于项目和目标平台。
汉斯·科赫

72

在纯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元素吗?
马特

2
p.offsetTop + p.parentNode.offsetTop您可以将其包装在递归函数调用中,就像几年前提出PPK一样。您可以更改函数以传递要增加的级别数,也可以使用选择器进行模仿$(selector).parents(parentSelector)。我更喜欢此解决方案,因为zepto实现仅在支持的浏览器上有效,getBoundingClientsRect而某些手机则不支持。
Torsten Walter

我以为getBoundingClientsRect得到了广泛的支持...如果有人知道哪个手机不支持它,我会很感兴趣(找不到关于它的任何手机支持表)。
大雄2014年

即使未标记,这也可能是最正确的答案。我的个人解决方案更改$(this).offset().leftthis.offsetLeft
adjwilli 2014年

这也可以修复jQuery.position()3d转换后的父级中的错误行为,非常感谢!
rassoh

6

我是在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,但其他浏览器也可以完成类似的工作。


1

将事件的偏移量添加到父元素偏移量中,以获取事件的绝对偏移量位置。

一个例子 :

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中。
David Spector '18

@DavidSpector词

1

因此,如果我们有一个id为“ child-element”的child元素,并且想要获得其相对于父元素的左/上位置,则说一个具有“ 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).offsetRelative("div.item-parent");

我看不到滚动占了。可能会发生很多奇怪的情况。
David Spector '18


0

使用纯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>

您是否对父节点和元素属性的所有可能情况进行了测试?这是否涉及滚动和嵌套滚动?
David Spector '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.