私はお互いの上に絶対に配置されたたくさんのdivを持っています。クリックイベントをそれらすべてにバインドすると、最上位のdivのみが応答します。カーソルの下にあるすべてのdivにイベントを送信するにはどうすればよいですか?
4 に答える
FelixKling の提案document.elementFromPoint()
と Amberlamps のフィドルを使用し、DOM インタラクションに jQuery を採用すると、次のようになりました。
$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
エラーが発生した場合でも、要素が再び表示されるようにするために使用されます。
2 つのメカニズムにより、クリック イベントを渡すかどうかを指定できます。
- ハンドラーを選択した要素のみにアタッチします (標準の jQuery)。
click.passThrough
に類似した、クリック イベントの名前空間event.stopPropagation()
。
個別にまたは組み合わせて、これらのメカニズムは、「パススルー」動作の接続と伝播を制御する際にある程度の柔軟性を提供します。たとえば、デモではp
、「b」要素からクラスを削除してみて、伝播動作がどのように変化したかを確認してください。
現状では、異なるアプリケーション レベルの動作を取得するには、コードを編集する必要があります。より一般化されたソリューションは次のようになります。
- アプリ固有の動作をプログラムでアタッチできるようにする
- と同様に、「passThrough」伝播をプログラムで禁止でき
event.stopPropagation()
ます。
これらの野心はどちらもclickPassthrough
、jQuery でイベントを確立し、"passThrough" 動作を基礎として実現することで実現できますが、それを実現するにはさらに多くの作業が必要になります。誰かが試してみたいと思うかもしれません。
これはあなたが思うほど簡単ではありません。これは私が思いついた解決策です。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);
};
}
クリック イベントを body 要素にアタッチして、すべてのクリック イベントがスクリプトによって認識されるようにします。
if(document.addEventListener) {
document.body.addEventListener("click", countDivs);
} else if(document.attachEvent) {
document.attachEvent("onclick", countDivs);
}
チェックするすべての div を繰り返します (ここで、好みの div 範囲に調整することをお勧めします)。計算されたスタイルを生成し、マウス座標が div の位置に幅と高さを加えた範囲内にあるかどうかを確認します。div がソース要素の場合はクリック イベントをトリガーしないでください。これは、クリック イベントがそれまでに発生しているためです。
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も追加しました
要素を完全にスタックする場合は、配置されたコンテナーにすべてをスタックし、この親からのイベントを処理する方が簡単な場合があります。その後、何も測定せずにその子を操作できます。
簡単な方法は、elementFromPoint() を使用することです。
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 = {};
}
});