11

我有一堆 div 绝对位于彼此之上。当我将点击事件绑定到所有这些时,只有顶部 div 响应。如何将事件发送到光标下的所有 div?

4

4 回答 4

5

采用 FelixKling 的使用建议document.elementFromPoint()和 Amberlamps 的小提琴,并使用 jQuery 进行 DOM 交互,我最终得到以下结果:

$divs = $("div").on('click.passThrough', function (e, ee) {
  var $el = $(this).hide();
  try {
    console.log($el.text());//or console.log(...) or whatever
    ee = ee || {
      pageX: e.pageX,
      pageY: e.pageY
    };
    var next = document.elementFromPoint(ee.pageX, ee.pageY);
    next = (next.nodeType == 3) ? next.parentNode : next //Opera
    $(next).trigger('click.passThrough', ee);
  } catch (err) {
      console.log("click.passThrough failed: " + err.message);
  } finally {
    $el.show();
  }
});

演示

try/catch/finally用于确保再次显示元素,即使发生错误。

两种机制允许通过或不通过点击事件:

  • 仅将处理程序附加到选定的元素(标准 jQuery)。
  • 命名空间点击事件,click.passThrough类似于event.stopPropagation().

单独或组合,这些机制在控制“passThrough”行为的连接和传播方面提供了一些灵活性。例如,在 DEMO 中,尝试p从“b”元素中删除类,看看传播行为是如何变化的。

就目前而言,需要编辑代码以获得不同的应用程序级行为。更通用的解决方案是:

  • 允许以编程方式附加特定于应用程序的行为
  • 允许以编程方式抑制“passThrough”传播,类似于event.stopPropagation().

这两个目标都可以通过clickPassthrough在 jQuery 中建立一个具有潜在“passThrough”行为的事件来实现,但要实现这一目标还需要做更多的工作。也许有人想试一试。

于 2013-01-19T16:54:03.613 回答
1

这并不像您想象的那么容易。这是我想出的解决方案。我只在 Chrome 中测试过,没有使用任何框架。

以下代码片段仅用于向div文档中的每个添加单击事件,触发时输出其类名。

var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++) {
    divs[i].onclick = function() {
        console.log("class clicked: " + this.className);
    };
}

将点击事件附加到正文元素,以便我们的脚本注意到每个点击事件。

if(document.addEventListener) {
    document.body.addEventListener("click", countDivs);
} else if(document.attachEvent) {
    document.attachEvent("onclick", countDivs);
}

遍历您要检查的所有 div(您可能需要在此处调整到您喜欢的 div 范围)。生成它们的计算样式并检查鼠标坐标是否在 div 的位置加上它的宽度和高度的范围内。当 div 是我们的源元素时不要触发 click 事件,因为此时已经触发了 click 事件。

function countDivs(e) {
    e = e || window.event;
    for(var i = 0; i < divs.length; i++) {
        var cStyle = window.getComputedStyle(divs[i]);
        if(divs[i] !== e.target && e.pageX >= parseInt(cStyle.left) && e.pageX <= (parseInt(cStyle.left) + parseInt(cStyle.width)) && e.pageY >= parseInt(cStyle.top) && e.pageY <= (parseInt(cStyle.top) + parseInt(cStyle.height))) {
            divs[i].click();
        }
    }
}

CSS:

.a, .b, .c {
  position: absolute;
  height: 100px;
  width: 100px;
  border: 1px #000 solid
}
.a {
  top: 100px;
  left: 100px;
}
.b {
  top: 120px;
  left: 120px;
}
.c {
  top: 140px;
  left: 140px;
}

HTML:

<div class="a"></div>
<div class="b"></div>
<div class="c"></div>

我还添加了一个jsFiddle

于 2013-01-19T12:52:37.890 回答
0

一种简单的方法是使用 elementFromPoint():

http://jsfiddle.net/SpUeN/1/

var clicks = 0,cursorPosition={};

$('div').click(function (e) {
    if(typeof cursorPosition.X === 'undefined') {
         cursorPosition.X = e.pageX;
        cursorPosition.Y = e.pageY;
    }
    clicks++;
    e.stopPropagation();
    $(this).addClass('hided');
    var underELEM = document.elementFromPoint(cursorPosition.X, cursorPosition.Y);
    if (underELEM.nodeName.toUpperCase() === "DIV") $(underELEM).click();
    else {
        $('#clicks').html("Clicks: " + clicks);
        $('.hided').removeClass('hided');
        clicks=0;
        cursorPosition = {};
    }
});
于 2013-01-19T13:02:05.300 回答
0

如果您绝对堆叠元素,则将它们全部堆叠在定位容器中并处理来自该父级的事件可能会更简单。然后,您可以操纵它的孩子而无需测量任何东西。

于 2013-01-19T14:05:06.673 回答