【问题标题】:Finding element's position relative to the document查找元素相对于文档的位置
【发布时间】:2011-04-08 17:37:11
【问题描述】:

确定元素相对于文档/正文/浏览器窗口的位置的最简单方法是什么?

现在我使用.offsetLeft/offsetTop,但是这个方法只给你相对于父元素的位置,所以你需要确定body元素有多少父元素,才能知道相对于body/浏览器的位置窗口/文档位置。

这个方法也比较麻烦。

【问题讨论】:

    标签: javascript dom


    【解决方案1】:

    你可以得到 topleft 而无需像这样遍历 DOM:

    function getCoords(elem) { // crossbrowser version
        var box = elem.getBoundingClientRect();
    
        var body = document.body;
        var docEl = document.documentElement;
    
        var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
        var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
    
        var clientTop = docEl.clientTop || body.clientTop || 0;
        var clientLeft = docEl.clientLeft || body.clientLeft || 0;
    
        var top  = box.top +  scrollTop - clientTop;
        var left = box.left + scrollLeft - clientLeft;
    
        return { top: Math.round(top), left: Math.round(left) };
    }
    

    【讨论】:

    • 这个答案没有考虑父母的偏移量。它仅相对于视口
    • @Nickey 这不是真的——视口位置,加上滚动偏移检查,产生相对于整个文档的坐标。
    • 在移动设备上可能有问题stackoverflow.com/a/32623832/962634需要研究
    • 为什么要减去clientTop/clientLeft?
    • @Teemoh clientTop / clientLeft 对应于 <html> 元素上的边框值。
    【解决方案2】:

    您可以使用element.getBoundingClientRect() 检索元素相对于视口的位置。

    然后使用document.documentElement.scrollTop计算视口偏移量。

    两者之和将给出元素相对于文档的位置:

    element.getBoundingClientRect().top + document.documentElement.scrollTop
    

    【讨论】:

    • 相对于视口与相对于文档不同。如果页面向下滚动一点,则相对于视口的顶部将比相对于文档的顶部小。
    • 他相对于视口开始并添加 scrollY 以使其相对于文档。
    • document.documentElement.scrollTop 在 Safari 中不起作用,请改用 window.scrollY
    • getBoundingClientRect() 计算元素及其所有后代的边界矩形。如果元素具有溢出:可见,则它可以有元素布局矩形之外的后代、比自身更大的后代、通过 CSS 变换任意移位的后代以及其他十几种边缘情况。
    【解决方案3】:

    您可以将offsetParent 遍历到 DOM 的顶层。

    function getOffsetLeft( elem )
    {
        var offsetLeft = 0;
        do {
          if ( !isNaN( elem.offsetLeft ) )
          {
              offsetLeft += elem.offsetLeft;
          }
        } while( elem = elem.offsetParent );
        return offsetLeft;
    }
    

    【讨论】:

    • 不,它没有,当任何父元素(尤其是 html 元素!!!)有边距、填充或边框时。
    • 关于边距的东西......它可能有助于将 box-sizing 设置为border-box......或类似的东西......没有什么是无法修复的......
    • 首先需要根据box-sizing来决定是否考虑border和margin。其次,应考虑折叠边距。最后,未来会出现更复杂的情况,这会使这个答案变得更糟。
    • 为什么这是公认的答案?这是过时的并且表现不佳。帮自己一个忙,并按照其他答案中的建议使用 getBoundingClientRect()。
    • 它必须是相对的某个元素。只为您提供全局 offsetLeft。我明白这是个问题,所以我猜对了。我有另一个与任何其他父母相关的案例。我想我可以重写这个。谢谢!
    【解决方案4】:

    我发现以下方法在处理触发 offsetTop/offsetLeft 的边缘情况时最可靠。

    function getPosition(element) {
        var clientRect = element.getBoundingClientRect();
        return {left: clientRect.left + document.body.scrollLeft,
                top: clientRect.top + document.body.scrollTop};
    }
    

    【讨论】:

      【解决方案5】:

      我建议使用

      element.getBoundingClientRect()
      

      建议here 而不是通过offsetLeftoffsetTopoffsetParent手动计算偏移量。按照建议here 在某些情况下*手动遍历会产生无效的结果。看到这个 Plunker:http://plnkr.co/pC8Kgj

      *当元素位于具有静态(=默认)定位的可滚动父级内部时。

      【讨论】:

      • 您也可以通过将scrollLeft和scrollTop合并到其中来进行偏移计算。
      • 但我发现 offsetLeftoffsetTop 没有考虑 CSS3 转换,getBoundingClientRect() 会考虑。因此,在这种情况下,结果可能无效。如果需要,可以使用 (element.getBoundingClientRect().left - parent.getBoundingClientRect().left) 获取元素相对于父元素的偏移量(如 offsetLeft)。
      • 应该 def 升得更高;这些值更有用,而且一键调用!
      【解决方案6】:

      document-offset3rd-party script)很有趣,它似乎利用了此处其他答案的方法。

      示例:

      var offset = require('document-offset')
      var target = document.getElementById('target')
      console.log(offset(target))
      // => {top: 69, left: 108} 
      

      【讨论】:

        【解决方案7】:

        对于那些想要获取元素相对于文档的各个位置的 x 和 y 坐标的人。

        const getCoords = (element, position) => {
          const { top, left, width, height } = element.getBoundingClientRect();
          let point;
          switch (position) {
            case "top left":
              point = {
                x: left + window.pageXOffset,
                y: top + window.pageYOffset
              };
              break;
            case "top center":
              point = {
                x: left + width / 2 + window.pageXOffset,
                y: top + window.pageYOffset
              };
              break;
            case "top right":
              point = {
                x: left + width + window.pageXOffset,
                y: top + window.pageYOffset
              };
              break;
            case "center left":
              point = {
                x: left + window.pageXOffset,
                y: top + height / 2 + window.pageYOffset
              };
              break;
            case "center":
              point = {
                x: left + width / 2 + window.pageXOffset,
                y: top + height / 2 + window.pageYOffset
              };
              break;
            case "center right":
              point = {
                x: left + width + window.pageXOffset,
                y: top + height / 2 + window.pageYOffset
              };
              break;
            case "bottom left":
              point = {
                x: left + window.pageXOffset,
                y: top + height + window.pageYOffset
              };
              break;
            case "bottom center":
              point = {
                x: left + width / 2 + window.pageXOffset,
                y: top + height + window.pageYOffset
              };
              break;
            case "bottom right":
              point = {
                x: left + width + window.pageXOffset,
                y: top + height + window.pageYOffset
              };
              break;
          }
          return point;
        };
        

        用法

        • getCoords(document.querySelector('selector'), 'center')

        • getCoords(document.querySelector('selector'), 'bottom right')

        • getCoords(document.querySelector('selector'), 'top center')

        【讨论】:

          【解决方案8】:

          如果你不介意使用 jQuery,那么你可以使用offset() 函数。如果您想了解有关此功能的更多信息,请参阅documentation

          【讨论】:

            【解决方案9】:

            http://www.quirksmode.org/js/findpos.html 解释了最好的方法,总而言之,你在正确的轨道上,你必须找到偏移量并遍历父母树。

            【讨论】:

              猜你喜欢
              • 2011-03-15
              • 2021-11-20
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-11-22
              • 2012-08-18
              相关资源
              最近更新 更多