有没有一种方法可以计算所有DOM元素的堆叠上下文,以便使用JavaScript比较上述位置的任何两个元素?

时间:2019-06-28 11:49:05

标签: javascript css dom

我正在尝试比较DOM中的任何两个元素,以查看它们是否要在同一区域(坐标重叠)上绘制(渲染在屏幕上),而一个区域要高于另一个区域。这个问题不是关于重叠计算,而是关于比较DOM树任何部分中的任意两个元素以获得上述位置(计算堆栈上下文以及z-index和HTML层次结构...)。

尽管我是这个领域的新手,但是我的方法还是会遍历并考虑规则和标准,为每个HTML元素分配一个数值。另一个问题是正确地获取它们。我找不到已经做到这一点的JS库。

有关CSS和完整代码示例,请参见... https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context

预期的输出是比较上方或下方位置(3D)的任何两个HTML元素的能力。如果我从这里的专业人员那里得到一个想法并能够实现它,我将分享我的代码。谢谢您的帮助。

2 个答案:

答案 0 :(得分:1)

npm上有一个名为fun beSave() { try { // some blackbox code } catch (e: Exception) { // handler } } 的{​​{3}},就是这样做的。

您可以通过以下方式安装它:

stacking-order
$ npm install stacking-order

或在脚本标签中使用package

import stackingOrder from 'stacking-order';

然后找到您要查找的内容,只需致电<script src="https://npmcdn.com/stacking-order"></script>

stackingOrder.compare(element1, element2)

答案 1 :(得分:1)

最简单的方法是使用document.elementsFromPoint(),它将在给定的位置按堆叠顺序为您提供所有元素。

复杂的部分是您需要找到两个元素都将相交的点。

下面的示例将搜索最左上角的共享点,并说明您必须更精确地定义约束,因为它会故意遗漏仍位于元素之间的元素:

test( 'red', 'blue' ); // -2 (blue:2, red:4)
test( 'red', 'green' ); // -2 (green:1, red:4) but at selected point blue is not visible
test( 'yellow', 'green' ); // -1 (yelow:3, green:1) but at selected point blue is not visible
test( 'blue', 'green' ); // -1 (blue:2, green: 1)

function test( class1, class2 ) {

  const elem1 = document.querySelector( '.' + class1 );
  const elem2 = document.querySelector( '.' + class2 );
  console.log( class1, class2, getStackDistance( elem1, elem2 ) );

}
function getStackDistance( elem1, elem2 ) {

  const shared_point = findSharedPoint( elem1, elem2 );
  if( !shared_point ) {
    console.error( 'no shared point' );
    return NaN;
  }
  const full_list = document.elementsFromPoint( shared_point.x, shared_point.y );

  return full_list.indexOf( elem1 ) - full_list.indexOf( elem2 );

}
// returns top-left-most shared point between two elements
function findSharedPoint( elem1, elem2 ) {

  const bbox1 = elem1.getBoundingClientRect( elem1 );
  const bbox2 = elem2.getBoundingClientRect( elem2 );
  const intersect_box = {
    left: Math.max( bbox1.left, bbox2.left ),
    right: Math.min( bbox1.right, bbox2.right ),
    top: Math.max( bbox1.top, bbox2.top ),
    bottom: Math.min( bbox1.bottom, bbox2.bottom )
  };
  if( intersect_box.left > intersect_box.right ||
    intersect_box.top > intersect_box.bottom ) {
    return null;  
  }

  return { x: intersect_box.left, y: intersect_box.top };
  
}
.box {
  width: 50px;
  height: 50px;
  position: absolute;
  opacity: 0.7;
}
.red {
  background: red;
  top: 20px;
  left: 20px;
  z-index: 4;
}
.blue {
  background: blue;
  top: 40px;
  left: 40px;
  z-index: 2;
}
.yellow {
  background: yellow;
  top: 10px;
  left: 20px;
  z-index: 3;
}
.green {
  background: green;
  top: 40px;
  left: 10px;
  z-index: 1;
}
<div class="box red"></div>
<div class="box blue"></div>
<div class="box yellow"></div>
<div class="box green"></div>