2013-01-19 16 views
8

Mam pęczek div postions absolutnie jeden na drugim. Kiedy wiążę zdarzenie click do wszystkich z nich, odpowiada tylko górny div. Jak wysłać zdarzenie do wszystkich elementów div pod kursorem?Jak propagować kliknięcie do wszystkich elementów div pod kursorem?

+0

Czy błąd, z powodu którego nie można zalogować się w konsoli, jest kliknięty? – defau1t

+0

@ defau1t: Chce, aby kliknięcie pojawiło się trzykrotnie w konsoli po kliknięciu tylko raz. – Amberlamps

+0

http://jsfiddle.net/vA5WQ/23/ – TheOne

Odpowiedz

3

Biorąc sugestię FelixKling do korzystania document.elementFromPoint() i skrzypce Amberlamps, a stosując jQuery do interakcji DOM, skończyło się z:

$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 służy do zapewnienia elementy ponownie wyświetlone, nawet jeśli wystąpi błąd.

dwa mechanizmy pozwalają zdarzenie click być przekazywane za pośrednictwem lub nie:

  • mocowania do obsługi tylko wybranych elementów (norma jQuery).
  • namespacing zdarzenia click, click.passThrough analogicznie do event.stopPropagation().

Mechanizmy te, oddzielnie lub w połączeniu, zapewniają pewną elastyczność w kontrolowaniu zajęcia i propagacji zachowania "passThrough". Na przykład w DEMO spróbuj usunąć klasę p z elementu "b" i zobacz, jak zmieniło się zachowanie propagacji.

W obecnej wersji kod musi zostać zmodyfikowany, aby uzyskać różne zachowania na poziomie aplikacji. Bardziej uogólnione rozwiązanie:

  • pozwala na programowe mocowania zachowania aplikacji specyficzne
  • umożliwienia programowego hamowanie „PASSTHROUGH” namnażania analogiczny do event.stopPropagation().

Obie te ambicje można osiągnąć, ustanawiając wydarzenie clickPassthrough w jQuery z zachowaniem "passThrough", ale wymaga to więcej pracy. Może ktoś chciałby spróbować.

+0

Uprzejmie proszę o kredyt, gdy kredyt jest należny. :) – TheOne

+0

Problemy pojawiają się, gdy element do kliknięcia jest kotwicą. –

+0

Jeśli ktoś inny ma taki sam problem jak ja: 'if ($ (next) .prop (" tagName ") === 'A') {window.location .href = $ (następny) .attr ('href'); } ' –

1

To nie jest takie proste, jak mogłoby się wydawać. To jest rozwiązanie, które wymyśliłem. Testowałem go tylko w Chrome i nie korzystałem z żadnej struktury.

Poniższy fragment służy tylko do dodania zdarzenia kliknięcia do każdego dokumentu div, który wyświetla jego nazwę klasy po uruchomieniu.

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

Dołączanie zdarzenie click do elementu ciała tak, że każde pojedyncze zdarzenie kliknięcia zauważony przez naszego skryptu.

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

Powtórz po wszystkich elementach div, które chcesz sprawdzić (możesz tutaj dostosować do preferowanego zakresu elementów div). Wygeneruj obliczony styl i sprawdź, czy współrzędne myszy mieszczą się w zakresie pozycji div oraz jej szerokości i wysokości. Nie wyzwalaj zdarzenia kliknięcia, gdy element div jest naszym elementem źródłowym, ponieważ zdarzenie kliknięcia zostało już wtedy uruchomione.

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> 

Dodałem także jsFiddle

+0

Jak działa twoje rozwiązanie? Czy możesz też wyjaśnić to, zamiast po prostu napisać kod? –

+1

@FelixKling: Dodałem kilka wyjaśnień. Myślę, że to wystarczy, prawda? – Amberlamps

+0

Świetnie! Zauważ, że 'e.srcElement' to tylko IE (Chrome dodał niektóre funkcje IE). Oficjalną właściwością elementu źródłowego jest 'e.target'. –

0

Prostym sposobem może być użycie 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 = {}; 
    } 
}); 
+0

Daje to moje "Kliknięcia: 3", gdy klikam tylko dwa dolne elementy div. – Amberlamps

+0

Przykro mi, zobacz aktualizację. –

0

Jeśli układanie elementów absolutnie może być prostsze do stosu je wszystkie w umieszczonym pojemnikiem i obsługi zdarzeń z tym rodzicem. Następnie można manipulować jego dziećmi bez konieczności pomiaru niczego.

Powiązane problemy