在Javascript中获取节点CSS的绝对位置

Get a node CSS absolute position in Javascript

本文关键字:位置 CSS 节点 Javascript 获取      更新时间:2023-09-26

我正试图用Javascript在另一个节点旁边(在内容的顶部)显示一个节点。我无法更改此节点的文档结构,需要在同一父节点下插入新节点。我想使用position:absolute来定位新节点,但似乎很难找到参考节点的位置。在引用节点上使用getBoundingClientRect()是不起作用的,因为该节点可能位于position:relative或position:absolute的祖先内部,并且getBoundiingClientRect)返回相对于文档的位置,该位置不能用作CSS position:绝对的坐标。

为了找到CSS的绝对位置,我真的必须循环遍历祖先才能找到第一个具有position:absolute或position:relative的祖先吗?或者有更容易的方法来获得这些信息吗?

注意:我正在寻找纯Javascript的答案。

更新:换句话说,当元素的CSS位置更改为"绝对"时,我正在寻找元素应该显示在同一位置的顶部/左侧像素位置。offsetTop/offsetLeft不是答案,因为元素可能在表内,在这种情况下,offsetParent是表单元格。

这里有一个递归解决方案:

function getCSSAbsolutePosition(el) {
  var pos= ('absolute relative').indexOf(getComputedStyle(el).position) == -1,
      rect1= {top: el.offsetTop * pos, left: el.offsetLeft * pos},
      rect2= el.offsetParent ? getCSSAbsolutePosition(el.offsetParent) : {top:0,left:0};
  return {top: rect1.top + rect2.top,
          left: rect1.left + rect2.left,
          width: el.offsetWidth,
          height: el.offsetHeight
         };
}

这个Fiddle中,需要突出显示一个红色句子。单击该按钮,将调用getCSSAbsolutePosition以获取其坐标、宽度和高度。一个新的div被放置在它下面(带有负z-Index),它有一个背景和边界。

请注意,"目标"div位于相对定位的div中的绝对定位表中,并应用了各种填充和边距。

这是我当前的解决方案。它有效,但我仍在寻找一个更简单的。

var getCSSAbsolutePosition = function getCSSAbsolutePosition(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;
        if (el) {
            var style = window.getComputedStyle(el);
            if (style.position == 'absolute' || style.position == 'relative')
                break;
        }
    }
    return {top: y, left: x};
}

您可以使用offsetLeftoffsetTop属性来获取元素相对于其offsetParent的位置。

这里有一个快速的例子,考虑到元素的offsetParent可能是一个表单元格,而没有定位,正如您正确指出的那样:

function positionOver(targetNode) {
    var el = document.createElement("div"),
        left = targetNode.offsetLeft,
        top = targetNode.offsetTop,
        testParent = targetNode.offsetParent;
    while (testParent) {
        if (
            testParent.tagName === "TD" ||
            testParent.tagName === "TH" ||
            testParent.tagName === "TABLE"
        ) {
            left += testParent.offsetLeft;
            top += testParent.offsetTop;
        }
        testParent = testParent.offsetParent;
    }
    el.style.left = left + "px";
    el.style.top = top + "px";
    el.classList.add("created");
    targetNode.parentNode.appendChild(el);
}
// Create and position a new element over #target
positionOver(document.querySelector("#target"));

CSS

.created {
    position: absolute;
    background: red;
    z-index: 10;
    width: 10px;
    height: 10px;
}

在这里打闹。

请注意,如果targetNode位于一个绝对定位的表中,则上述函数将无法按预期工作。