检查是否可以与DOM元素进行交互

Ale*_*s G 8 javascript css jquery dom

在我的html5应用程序中,我做了很多动态dom元素创建/操作.在某些情况下,我需要验证用户是否可以"点击"元素(例如div)."可点击"表示满足以下两个条件:

  • 它的计算CSS样式意味着它的实际显示(即displayvisibility元素的性质和它的所有的父母)
  • 它不会被任何其他元素所掩盖,无论是使用更高的z-index还是后来创建的绝对定位的元素 - 在任何级别的DOM上,而不仅仅是它的兄弟姐妹.

我可以使用纯JS或jQuery.使用jQuery很容易检查第一部分(即使用.is(':visible').但是,如果我有一个被另一个元素遮挡的元素,它仍会返回true.

如何检查元素是否真正可点击?

I w*_*ce. 2

它使用标准视频游戏风格的碰撞测试来确定一个项目是否占据了另一个项目所占据的全部空间。我不会费心解释这部分,你可以看到其他答案。

对我来说,弄清楚这一点的困难部分是尝试获取每个元素的 z-index 以确定一个元素实际上是在另一个元素的顶部还是底部。首先,我们检查定义的 z-index,如果没有设置,我们检查父元素,直到到达文档。如果我们一直到达文档而没有找到定义的 z-index,我们知道首先渲染的项目(文档中的标记较高)将位于下面。

我已经将其实现为 jQuery 插件..$("#myElement").isClickable()

$.fn.isClickable = function() {
  if (!this.length) return false;

  const getZIndex = e => {
    if (e === window || e === document) return 0;
    var z = document.defaultView.getComputedStyle(e).getPropertyValue('z-index');
    if (isNaN(z)) return getZIndex(e.parentNode);
    else return z;
  };

  var width = this.width(),
    height = this.height(),
    offset = this.offset(),
    zIndex = getZIndex(this[0]),
    clickable = true,
    target = this[0],
    targetIsBefore = false;

  $("body *").each(function() {
    if (this === target) targetIsBefore = true;
    if (!$(this).is(":visible") || this === target) return;

    var e_width = $(this).width(),
      e_height = $(this).height(),
      e_offset = $(this).offset(),
      e_zIndex = getZIndex(this),

      leftOfTarget = offset.left >= e_offset.left,
      rightOfTarget = width + offset.left <= e_width + e_offset.left,
      belowTarget = offset.top >= e_offset.top,
      aboveTarget = height + offset.top <= e_height + e_offset.top,
      behindTarget = e_zIndex === zIndex ? targetIsBefore : e_zIndex > zIndex;

    if (leftOfTarget && rightOfTarget && belowTarget && aboveTarget && behindTarget) clickable = false;
  });

  return clickable;
};

$(".clickme").click(function() {
  alert("u clicked " + this.id)
});

$(".clickme").each(function() {
  console.log("#"+this.id, $(this).isClickable() ? "is clickable" : "is NOT clickable");
})
Run Code Online (Sandbox Code Playgroud)
#item1 {
  background: rgba(230, 30, 43, 0.3);
  position: absolute;
  top: 3px;
  left: 4px;
  width: 205px;
  height: 250px;
}

#item2 {
  background: rgba(30, 250, 43, 0.3);
  position: absolute;
  top: 100px;
  left: 50px;
  width: 148px;
  height: 50px;
}

#item3 {
  background: rgba(30, 25, 110, 0.3);
  position: absolute;
  top: 23px;
  left: 101px;
  width: 32px;
  height: 100px;
}

#item4 {
  background: rgba(159, 25, 110, 0.3);
  position: absolute;
  top: 10px;
  left: 45px;
  width: 23px;
  height: 45px;
  z-index: -111
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="item1" class='clickme'></div>
<div id="item2" class='clickme'></div>
<div id="item3" class='clickme'></div>
<div id="item4" class='clickme'></div>
Run Code Online (Sandbox Code Playgroud)