【问题标题】:Get a node CSS absolute position in Javascript在Javascript中获取节点CSS绝对位置
【发布时间】:2015-04-03 05:54:16
【问题描述】:

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

我是否真的必须遍历祖先才能找到第一个具有 position:absolute 或 position:relative 的祖先才能找到 CSS 绝对位置,还是有更简单的方法来获取此信息?

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

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

【问题讨论】:

  • Javascript: get position/offset of element relative to a parent container? 的可能重复项 - 接受的答案详细说明了纯 JavaScript 属性
  • 我看不出这些问题有什么关系:我不是在寻找相对于父母的位置。
  • 我添加了一个示例来演示如何使用offsetLeftoffsetTop。也许该问题的标题具有误导性,但解决方案是相同的 - 您需要相对于 offsetParent 的位置,这实际上可能不是直接父级 - 它指的是具有绝对或相对定位的最近祖先。
  • 这是一个实验的小提琴:jsfiddle.net/ujzppwwd

标签: javascript css


【解决方案1】:

这是一个递归解决方案:

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
         };
}

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

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

【讨论】:

  • 在您的小提琴中,您将新元素附加到 document.body。我的要求之一是将新元素添加到目标的父级内(“我需要在同一个父级下插入新节点”;在你的小提琴中,那将是 td)。
  • 我想我明白了。见jsfiddle.net/mqb9ua12 这是你要找的吗?如果是这样,我会更新我的回复。
  • 这更像是它,但如果你在 td 和目标之间有一个 div,你的新小提琴就不起作用:jsfiddle.net/0ohj6muy
  • 我很困惑为什么你的第二把小提琴奏效了,我发现了原因:“div.style.left= (rect1.left - rect2.left) + 'px; 中的语法错误; '"(左侧属性未设置)。
  • 哈,不错。关于中间的 div 很好。这比我想象的要复杂。
【解决方案2】:

您可以使用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;
}

Fiddle here.

请注意,如果 targetNode 在绝对定位的表中,上述函数将无法正常工作。

【讨论】:

  • offsetLeft 和 offsetTop 不是答案,因为父级可能不是绝对定位的。另一个祖先可能是(或不是:我没有假设任何关于祖先的事情)。此外,目标节点也可能不是绝对定位的。
  • 你的意思是这样的? jsfiddle.net/ju3uyva3/3 - 使用完全相同的技术,在目标或父节点上根本没有定位。
  • ...和this 有一个有定位的祖先。
  • 你是对的,当祖先绝对定位时它可以工作(我误解了什么 offsetLeft/offsetTop 是),但如果元素在表格内,它就不起作用:jsfiddle.net/j1jpydu7(因为那时 offsetLeft是相对于第一个表格单元祖先的)。我的解决方案仍然适用于表格。
  • 嗯,你是对的!我错过了文档中的那个注释。有趣的问题:) 我更新的答案希望能解决这个问题,只需检查元素的offsetParents 是否是表格单元格并添加它们的偏移量。我想在循环方面我们几乎回到了原来的方法。
【解决方案3】:

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

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};
}

【讨论】:

    猜你喜欢
    • 2017-12-06
    • 2017-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多