你能用 JavaScript 判断一个元素是不是正在接触另一个元素吗?

Posted

技术标签:

【中文标题】你能用 JavaScript 判断一个元素是不是正在接触另一个元素吗?【英文标题】:Can you tell if one element is touching another using JavaScript?你能用 JavaScript 判断一个元素是否正在接触另一个元素吗? 【发布时间】:2015-07-07 03:41:05 【问题描述】:

我想使用 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!

【问题讨论】:

check collision between certain divs?的可能重复 通过计算元素顶部/左侧和宽度/高度你可以做到:) ***.com/questions/442404/… PS:上面的评论和我说的一样......哦,好吧......:D跨度> 【参考方案1】:

更完整的解决方案

下面是对this answer 中的重叠检测函数的“普通旧 JavaScript”重写,改写为标题为“jQuery/Javascript collision detection”的问题。

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

令人惊讶的是,原生 JavaScript 使用得到良好支持的 (IE4+) Element.getBoundingClientRect() 方法简化了这项任务,该方法返回创建 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>

【讨论】:

是的。请参阅this example with 99 overlapping boxes 尽管在某些时候您可能会开始看到明显的性能下降,因为此解决方案会循环遍历所有选定的元素(在本例中为 class="box"),获取每个元素的位置并将其与目标元素进行比较。 您可以通过在comparePostions() 中使用Math.min(p1, p2) 来进一步收紧此代码。 @JesseJamesBurton 比较是一样的,但是赋值不同。我可以存储比较的结果,并在每个表达式的三进制中使用它来防止冗余操作。 啊,好吧,我明白了,所以基本上对于每次比较,您总是将 1 个项目分配给 r1,将一个项目分配给 r2,然后正确吗?感谢您的澄清! 太棒了!这完全有道理:)【参考方案2】:

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


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

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

    暂时隐藏目标元素,然后使用document.elementFromPoint(x, y) (src) 获取该位置的最顶层元素,然后检查它的类名以进行比较(如果您可以比较任何属性或属性,更喜欢)。

    通过此方法实现跨浏览器兼容行为 阅读: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>

【讨论】:

以上是关于你能用 JavaScript 判断一个元素是不是正在接触另一个元素吗?的主要内容,如果未能解决你的问题,请参考以下文章

你能用C ++破坏和重建一个向量的元素吗?

jQuery:你能用 jQuery 找到所选元素的不透明度吗?

你能用同样的方法重新保存一个 Django 对象吗

你能用 AngularJS 做条件格式化吗?

JS判断输入值是不是为正整数

你能用 swift 将字符串附加到 Firebase 数组吗