检索HTML元素相对于浏览器窗口的位置(X,Y)

2020/09/16 08:31 · javascript ·  · 0评论

我想知道如何相对于浏览器窗口获取HTML元素(例如imgdiv在JavaScript中)的X和Y位置

正确的方法是使用element.getBoundingClientRect()

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);

Internet Explorer自从您很可能就一直在支持此功能,并且最终在CSSOM Views中对其进行了标准化所有其他浏览器很早以前就采用了它

一些浏览器还返回height和width属性,尽管这是非标准的。如果您担心与旧版浏览器的兼容性,请查看此答案的修订版以实现优化的降级实现。

返回的值element.getBoundingClientRect()是相对于视口的。如果您需要相对于另一个元素的矩形,只需从另一个矩形中减去一个矩形:

var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;

alert('Element is ' + offset + ' vertical pixels from <body>');

库需要一定的长度才能获得元素的准确偏移量。

这是一个简单的函数,可以在我尝试过的所有情况下都能完成工作。

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}
var x = getOffset( document.getElementById('yourElId') ).left; 

这为我工作(从最高投票答案修改):

function getOffset(el) {
  const rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.scrollX,
    top: rect.top + window.scrollY
  };
}

使用这个我们可以打电话

getOffset(element).left

要么

getOffset(element).top

如果你想完成它只是在javascript,这里有一些一个衬垫 使用getBoundingClientRect()

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

第一行将offsetTop相对于文档返回“ Y”。第二行将返回offsetLeft相对于文档的X。

getBoundingClientRect() 是一个javascript函数,它返回元素相对于窗口视口的位置。

大多数浏览器上的HTML元素将具有:

offsetLeft
offsetTop

这些参数指定元素相对于具有布局的最近父元素的位置。通常可以通过offsetParent属性访问此父级。

IE和FF3有

clientLeft
clientTop

这些属性不太常见,它们在其父级客户区中指定元素位置(填充区是客户区的一部分,而边界和边距则不是)。

如果页面包含-至少-任何“ DIV”,则由meouw给出的函数会抛出“ Y”值超出当前页面限制。为了找到确切的位置,您需要同时处理offsetParent和parentNode。

尝试下面给出的代码(已检查FF2):


var getAbsPosition = function(el){
    var el2 = el;
    var curtop = 0;
    var curleft = 0;
    if (document.getElementById || document.all) {
        do  {
            curleft += el.offsetLeft-el.scrollLeft;
            curtop += el.offsetTop-el.scrollTop;
            el = el.offsetParent;
            el2 = el2.parentNode;
            while (el2 != el) {
                curleft -= el2.scrollLeft;
                curtop -= el2.scrollTop;
                el2 = el2.parentNode;
            }
        } while (el.offsetParent);

    } else if (document.layers) {
        curtop += el.y;
        curleft += el.x;
    }
    return [curtop, curleft];
};

您可以添加两个属性以Element.prototype获取任何元素的顶部/左侧。

Object.defineProperty( Element.prototype, 'documentOffsetTop', {
    get: function () { 
        return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 );
    }
} );

Object.defineProperty( Element.prototype, 'documentOffsetLeft', {
    get: function () { 
        return this.offsetLeft + ( this.offsetParent ? this.offsetParent.documentOffsetLeft : 0 );
    }
} );

这样称呼:

var x = document.getElementById( 'myDiv' ).documentOffsetLeft;

这是一个将结果与jQuery offset().top比较的演示.lefthttp : //jsfiddle.net/ThinkingStiff/3G7EZ/

在不使用递归函数的情况下,有效地检索相对于页面的位置:(还包括IE)

var element = document.getElementById('elementId'); //replace elementId with your element's Id.
var rect = element.getBoundingClientRect();
var elementLeft,elementTop; //x and y
var scrollTop = document.documentElement.scrollTop?
                document.documentElement.scrollTop:document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft?                   
                 document.documentElement.scrollLeft:document.body.scrollLeft;
elementTop = rect.top+scrollTop;
elementLeft = rect.left+scrollLeft;

这样的事情怎么样,通过传递元素的ID并返回左或上,我们也可以将它们组合起来:

1)找到左

function findLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.left + window.scrollX;
} //call it like findLeft('#header');

2)找到顶部

function findTop(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.top + window.scrollY;
} //call it like findTop('#header');

3)一起找到左和上

function findTopLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return {top: rec.top + window.scrollY, left: rec.left + window.scrollX};
} //call it like findTopLeft('#header');

使用JavaScript框架可能会更好地为您提供服务,该框架具有以与浏览器无关的方式返回此类信息(甚至更多!)的功能。这里有一些:

使用这些框架,您可以执行以下操作:
$('id-of-img').top
获取图像的y像素坐标。

jQuery .offset()将获取第一个元素的当前坐标,或设置匹配元素集中相对于文档的每个元素的坐标。

我已经采用@meouw的答案,将其添加到允许边框的clientLeft中,然后创建了三个版本:

getAbsoluteOffsetFromBody-与@meouw相似,它获取相对于文档正文或html元素的绝对位置(取决于怪癖模式)

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

getAbsoluteOffsetFromRelative-返回相对于具有位置: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中至少有一个可疑代码,假设浏览器的行为正常,应该可以,但完全没有测试其余部分。

如果使用jQuery,则Dimensions插件非常出色,可让您精确指定所需的内容。

例如

相对位置,绝对位置,不带填充的绝对位置,带填充...

它还在继续,让我们说您可以做很多事情。

再加上使用jQuery的好处是文件大小轻巧且易于使用,如果没有它,您将不会再使用JavaScript。

如果您使用的是jQuery,这可能是一个简单的解决方案:

<script>
  var el = $("#element");
  var position = el.position();
  console.log( "left: " + position.left + ", top: " + position.top );
</script>

小与小的区别

function getPosition( el ) {
    var x = 0;
    var y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
    x += el.offsetLeft - el.scrollLeft;
    y += el.offsetTop - el.scrollTop;
    el = el.offsetParent;
    }
    return { top: y, left: x };
}

看一个坐标示例:http :
//javascript.info/tutorial/coordinates

这是我设法创建的最好的代码(与jQuery的offset()不同,它也可以在iframe中使用)。似乎webkit有一些不同的行为。

根据meouw的评论:

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        // chrome/safari
        if ($.browser.webkit) {
            el = el.parentNode;
        } else {
            // firefox/IE
            el = el.offsetParent;
        }
    }
    return { top: _y, left: _x };
}

我发现的最干净的方法是jQuery所使用技术的简化版本offset类似于其他答案的开头getBoundingClientRect; 然后使用windowdocumentElement来调整滚动位置以及上的边距body(通常是默认值)之类的内容。

var rect = el.getBoundingClientRect();
var docEl = document.documentElement;

var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;

尽管很可能在这么多答案的最底端都看不到这一点,但此处的最佳解决方案对我而言并不起作用。

据我所知,其他答案都无济于事。

情况

在HTML5页面中,我有一个菜单,该菜单是标题中的nav元素(不是THE标题,而是另一个元素中的标题)。


我希望导航在用户滚动到顶部时停留在顶部,但是在此之前,页眉是绝对定位的(因此我可以将其稍微覆盖一下)。


上面的解决方案从未触发更改,因为.offsetTop不会更改,因为这是绝对定位的元素。
此外,.scrollTop属性只是最上面的元素的顶部...也就是说0,并且始终为0。


我使用这两项进行的任何测试(与getBoundingClientRect结果相同)都不会告诉我导航栏的顶部是否曾经滚动到可见页面的顶部(再次,如控制台中所报告的,它们只是在滚动时保持相同的数字)发生了)。

解决


方案对我来说,解决方案是利用

window.visualViewport.pageTop

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

也许无需多说,每当我处理滚动时,我都希望使用此解决方案以编程方式响应被滚动元素的运动。

希望它可以帮助其他人。

重要说明:这似乎目前在Chrome和Opera中有效,并且在Firefox(6-2018)中绝对不可用 ...直到Firefox支持visualViewport之前,我建议不要使用此方法,(我希望他们尽快使用此方法...比其余的更有意义)。

更新:


只是有关此解决方案的说明。

虽然我仍然发现我发现的内容对于“ ...以编程方式响应所滚动元素的移动”的情况非常有价值。适用。对于我遇到的问题,更好的解决方案是使用CSS设置位置:粘性在元素上。使用sticky,您可以不使用javascript就将元素保留在顶部(注意:有时候,这不能像将元素更改为fixed那样有效,但是对于大多数使用sticky的方法可能会更好)

UPDATE01:


我意识到对于另一个页面,我有一个要求,我需要在一个稍微复杂的滚动设置中检测元素的位置(视差以及作为消息一部分滚动过去的元素)。
我意识到在这种情况下,以下内容提供了我用来确定何时进行操作的值:

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

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

我这样做是为了让它与旧的浏览器交叉兼容。

// For really old browser's or incompatible ones
    function getOffsetSum(elem) {
        var top = 0,
            left = 0,
            bottom = 0,
            right = 0

         var width = elem.offsetWidth;
         var height = elem.offsetHeight;

        while (elem) {
            top += elem.offsetTop;
            left += elem.offsetLeft;
            elem = elem.offsetParent;
        }

         right = left + width;
         bottom = top + height;

        return {
            top: top,
            left: left,
            bottom: bottom,
            right: right,
        }
    }

    function getOffsetRect(elem) {
        var box = elem.getBoundingClientRect();

        var body = document.body;
        var docElem = document.documentElement;

        var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
        var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;

        var clientTop = docElem.clientTop;
        var clientLeft = docElem.clientLeft;


        var top = box.top + scrollTop - clientTop;
        var left = box.left + scrollLeft - clientLeft;
        var bottom = top + (box.bottom - box.top);
        var right = left + (box.right - box.left);

        return {
            top: Math.round(top),
            left: Math.round(left),
            bottom: Math.round(bottom),
            right: Math.round(right),
        }
    }

    function getOffset(elem) {
        if (elem) {
            if (elem.getBoundingClientRect) {
                return getOffsetRect(elem);
            } else { // old browser
                return getOffsetSum(elem);
            }
        } else
            return null;
    }

有关JavaScript中坐标的更多信息,请访问:http : //javascript.info/tutorial/coordinates

要获取元素的总偏移量,您可以递归求和所有父偏移量:

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

使用此实用程序功能,dom元素的总顶部偏移为:

el.offsetTop + getParentOffsets(el);
/**
 *
 * @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;
}

感谢ThinkingStiff答案,这是它只是另一个版本。

我成功地使用了Andy E的解决方案来根据用户单击表行中的链接来定位bootstrap 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');");
        }
    });
}

希望这对某人有帮助,这篇文章对您有所帮助。

经过大量研究和测试,这似乎可行

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,输出

只是以为我也会把它扔在那里。

我无法在较旧的浏览器中对其进行测试,但它可以在前3个中的最新版本中运行。:)

Element.prototype.getOffsetTop = function() {
    return ( this.parentElement )? this.offsetTop + this.parentElement.getOffsetTop(): this.offsetTop;
};
Element.prototype.getOffsetLeft = function() {
    return ( this.parentElement )? this.offsetLeft + this.parentElement.getOffsetLeft(): this.offsetLeft;
};
Element.prototype.getOffset = function() {
    return {'left':this.getOffsetLeft(),'top':this.getOffsetTop()};
};

这很容易,因为在JS中有两行:

var elem = document.getElementById("id");    
alert(elem.getBoundingClientRect());

由于不同的浏览器以不同的方式呈现边框,填充,边距等。我编写了一个小函数来检索要精确定位的每个根元素中特定元素的顶部和左侧位置:

function getTop(root, offset) {
    var rootRect = root.getBoundingClientRect();
    var offsetRect = offset.getBoundingClientRect();
    return offsetRect.top - rootRect.top;
}

要获取左侧位置,您必须返回:

    return offsetRect.left - rootRect.left;

获取div相对于左侧和顶部的位置

  var elm = $('#div_id');  //get the div
  var posY_top = elm.offset().top;  //get the position from top
  var posX_left = elm.offset().left; //get the position from left 
本文地址:http://javascript.askforanswer.com/jiansuohtmlyuansuxiangduiyuliulanqichuangkoudeweizhixy.html
文章标签: ,   ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!