你能用 JavaScript 判断一个元素是否与另一个元素接触吗?

Can you tell if one element is touching another using JavaScript?

我想使用 JavaScript 检查一个 div 元素(可以拖动)是否正在接触另一个 div 元素。

这是一些代码:

<div id="draggable" style="position: absolute;  top: 100px; left: 200px; background-color: red;  width: 100px; height: 100px;"></div>
<div style="background-color: green; width: 100px; height: 100px;"></div>

这可以做到吗?

如果是,怎么做?

编辑: 我不想使用 jQuery,只是老旧 JavaScript!

更新: 我现在意识到,这只说明了目标元素左上角的交集,因此没有提供完整的解决方案。但我会把它留给后代,以防有人发现它对其他用途有用。


使用element.getBoundingClientRect()document.elementFromPoint()

  1. 可以使用element.getClientBoundingRect()(src)获取目标(点击、拖动等)元素的位置

  2. 暂时隐藏目标元素,然后使用document.elementFromPoint(x, y)src)获取该位置的最顶层元素,然后检查它是class用于比较的名称(如果愿意,您可以比较任何属性或 属性)。

    通过此方法实现跨浏览器兼容行为 阅读:document.elementFromPoint – a jQuery solution (你不 必须使用 jQuery 才能达到此结果。该方法可以是 以纯 JS 复制。)


附录:

我只展示了检测重叠的功能,而不是展示了拖放或拖拽移动功能,因为不清楚你正在尝试实现其中的哪一个,如果有的话,还有显示如何完成各种拖动模式的其他答案。

在任何情况下,您都可以将下面的detectCollision()功能与任何拖动解决方案结合使用。


var box2 = document.getElementById('box2'),
    box3 = document.getElementById('box3');
box2.onclick = detectCollision;
box3.onclick = detectCollision;

function detectCollision(e) {
    var elem        = e.target,
        elemOffset  = elem.getBoundingClientRect(),
        elemDisplay = elem.style.display;
    
    // Temporarily hide element
    elem.style.display = 'none';
    
    // Check for top-most element at position
    var topElem = document.elementFromPoint(elemOffset.left, elemOffset.top);

    // Reset element's initial display value.
    elem.style.display = elemDisplay;

    // If a top-most element is another box
    if (topElem.className.match(/box/)) {
        alert(elem.id + " is touching " + topElem.id);
    } else {
        alert(elem.id + " isn't touching another box.");
    };
}
#box1 {
    background-color: LightSeaGreen;
}
#box2 {
    top: 25px;
    left: -25px;
    background-color: SandyBrown;
}
#box3 {
    background-color: SkyBlue;
}
.box {
    position: relative;
    display: inline-block;
    width: 100px;
    height: 100px;    
}
.clickable {
    cursor: pointer;
}
<div class="box" id="box1"></div>
<div class="box clickable" id="box2"></div>
<div class="box clickable" id="box3"></div>

更完整的解决方案

下面是 "plain old JavaScript" 对 this answer to the question titled "jQuery/Javascript collision detection 中的重叠检测函数的重写。

两者之间唯一真正的区别是替换了使用 jQuery 获取元素位置和宽度以计算边界框。

令人惊讶的是,原生 JavaScript 使用得到良好支持的 (IE4+) Element.getBoundingClientRect() 方法使这项任务变得更容易,returns 创建位置矩阵所需的四个值由getPositions 函数。

我为框添加了一个点击处理程序,作为您如何使用该函数将目标(点击、拖动等)元素与一组选定元素进行比较的简单演示。 不过,我承认 jQuery 使 DOM 选择和事件绑定比原生 JS 更容易。

var boxes = document.querySelectorAll('.box');

boxes.forEach(function (el) {
  if (el.addEventListener) {
      el.addEventListener('click', clickHandler);
  } else {
      el.attachEvent('onclick', clickHandler);
  }
})

var detectOverlap = (function () {
    function getPositions(elem) {
        var pos = elem.getBoundingClientRect();
        return [[pos.left, pos.right], [pos.top, pos.bottom]];
    }

    function comparePositions(p1, p2) {
        var r1, r2;
        if (p1[0] < p2[0]) {
          r1 = p1;
          r2 = p2;
        } else {
          r1 = p2;
          r2 = p1;
        }
        return r1[1] > r2[0] || r1[0] === r2[0];
    }

    return function (a, b) {
        var pos1 = getPositions(a),
            pos2 = getPositions(b);
        return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]);
    };
})();

function clickHandler(e) {
    
    var elem     = e.target,
        elems    = document.querySelectorAll('.box'),
        elemList = Array.prototype.slice.call(elems),
        within   = elemList.indexOf(elem),
        touching = [];
    if (within !== -1) {
        elemList.splice(within, 1);
    }
    for (var i = 0; i < elemList.length; i++) {
        if (detectOverlap(elem, elemList[i])) {
            touching.push(elemList[i].id);
        }
    }
    if (touching.length) {
        console.log(elem.id + ' touches ' + touching.join(' and ') + '.');
        alert(elem.id + ' touches ' + touching.join(' and ') + '.');
    } else {
        console.log(elem.id + ' touches nothing.');
        alert(elem.id + ' touches nothing.');
    }

}
#box1 {
    background-color: LightSeaGreen;
}
#box2 {
    top: 25px;
    left: -25px;
    background-color: SandyBrown;
}
#box3 {
    left: -50px;
    background-color: SkyBlue;
}
#box4 {
    background-color: SlateGray;
}
.box {
    position: relative;
    display: inline-block;
    width: 100px;
    height: 100px;
    color: White;
    font: bold 72px sans-serif;
    line-height: 100px;
    text-align: center;
    cursor: pointer;
}
.box:hover {
    color: Black;
}
<p>Click a box to see which other boxes are detected as touching it.<br />
<em>If no alert dialog box appears, open your console to view messages.</em></p>
<div class="box" id="box1">1</div>
<div class="box" id="box2">2</div>
<div class="box" id="box3">3</div>
<div class="box" id="box4">4</div>