如何将单击传播到光标下的所有div?

时间:2013-01-19 12:21:16

标签: javascript jquery css javascript-events

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

4 个答案:

答案 0 :(得分:3)

考虑到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();
  }
});

<强> DEMO

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

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

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

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

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

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

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

答案 1 :(得分: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);
    };
}

将click事件附加到body元素,以便我们的脚本注意到每个单击事件。

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

答案 2 :(得分: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 = {};
    }
});

答案 3 :(得分:0)

如果要绝对堆叠元素,将它们全部堆叠在已定位的容器中可能更简单,并处理来自此父级的事件。然后,您可以操纵其孩子,而无需进行任何衡量。