Rileva solo l'evento click sullo pseudo-elemento


213

Il mio codice è:

p {
    position: relative;
    background-color: blue;
}

p:before {
    content: '';
    position: absolute;
    left:100%;
    width: 10px;
    height: 100%;
    background-color: red;
}

Si prega di vedere questo violino: http://jsfiddle.net/ZWw3Z/5/

Vorrei innescare un evento click solo sullo pseudo-elemento (il bit rosso). Cioè, non voglio che l'evento click venga attivato sul bit blu.


1
Che ne dici di controllare pos cliccato? stackoverflow.com/questions/3234977/...

Si prega di leggere la mia soluzione precedentemente pubblicato qui .
Amr

Forse una buona soluzione QUI .
Reza Mamun,

Risposte:


218

Non è possibile; gli pseudo-elementi non fanno affatto parte del DOM, quindi non puoi associare alcun evento direttamente a loro, puoi solo legare ai loro elementi principali.

Se devi avere un gestore di clic solo sulla regione rossa, devi creare un elemento figlio, come un span, posizionarlo subito dopo il <p>tag di apertura , applicare stili al p spanposto di p:beforee associarlo.


108
Sembra che nei browser moderni questo sia un po 'possibile con pointer-eventsvalori diversi per l'elemento stesso e il suo pseudo elemento: jsfiddle.net/ZWw3Z/70
Ilya Streltsyn

5
@Ilya Streltsyn incredibile - non la risposta "corretta" (non funzionerebbe se fosse necessario anche fare clic sull'elemento) ma funziona alla grande per un "pulsante di chiusura" sui div
RozzA

pointer-eventsnon sembrano fare il trucco per IE9, secondo il jsfiddel pubblicato da Ilya.
user393274

@ user393274: IE9 non supporta eventi puntatore al di fuori di SVG.
BoltClock

1
@theyuv no, su quella pagina è possibile fare clic su tutta la riga, sia a sinistra che a destra dal link. Solo il collegamento stesso ha un gestore di clic diverso, quindi facendo clic su di esso non si attiva la sottostruttura di piegatura / apertura.
Ilya Streltsyn,

131

In realtà, è possibile. Puoi verificare se la posizione cliccata era al di fuori dell'elemento, poiché ciò accadrà solo se ::beforeo è ::afterstato cliccato.

Questo esempio controlla solo l'elemento a destra ma dovrebbe funzionare nel tuo caso.

span = document.querySelector('span');

span.addEventListener('click', function (e) {
    if (e.offsetX > span.offsetWidth) {
        span.className = 'c2';
    } else {
        span.className = 'c1';
    }
});
div { margin: 20px; }
span:after { content: 'AFTER'; position: absolute; }

span.c1 { background: yellow; }
span.c2:after { background: yellow; }
<div><span>ELEMENT</span></div>

JSFiddle


1
Non funziona per me, il testo viene evidenziato quando faccio clic su uno dei due. Utilizzando Firefox, se è importante (non dovrebbe).
Flater,

2
per firefox: jsfiddle.net/wC2p7/16 . Se si lavora con elementi nidificati, potrebbe essere necessario calcolare gli offset nidificati in modo appropriato (ad es. JQuery: $ (e.target) .offset (). Left)
bebbi

1
Fantastico uomo grazie, funziona. Ma in Firefox e altri browser conformi agli standard, per verificare se il mouse sopra :afterè necessario controllare if (e.clientX > span.offsetLeft + span.offsetHeight)poiché questi browser non hanno la e.offsetXproprietà. Fiddle: jsfiddle.net/Noitidart/wC2p7/18
Noitidart

5
Sarebbe ancora più interessante se jQuery decidesse di supportare, $('a:after').on('click', fn)ma non vedo davvero che ciò accada: p
Linus Unnebäck

25
Questo in realtà non funzionerà se ::beforeo ::afterè posizionato all'interno dell'elemento.
laconbass,

74

Sui browser moderni puoi provare con la proprietà css pointer-events (ma porta all'impossibilità di rilevare eventi del mouse sul nodo genitore):

p {
    position: relative;
    background-color: blue;
    color:#ffffff;
    padding:0px 10px;
    pointer-events:none;
}
p::before {
    content: attr(data-before);
    margin-left:-10px;
    margin-right:10px;
    position: relative;
    background-color: red;
    padding:0px 10px;
    pointer-events:auto;
}

Quando il target dell'evento è il tuo elemento "p", sai che è il tuo "p: before".

Se è ancora necessario rilevare gli eventi del mouse sulla pagina principale, è possibile considerare la possibilità di modificare la struttura HTML. È possibile aggiungere un tag span e il seguente stile:

p span {
    background:#393;
    padding:0px 10px;
    pointer-events:auto;
}

I target dell'evento ora sono sia gli elementi "span" che "p: before".

Esempio senza jquery: http://jsfiddle.net/2nsptvcu/

Esempio con jquery: http://jsfiddle.net/0vygmnnb/

Ecco l'elenco dei browser che supportano gli eventi puntatore: http://caniuse.com/#feat=pointer-events


Non so perché sia ​​il nodo genitore. Stai dicendo che se io l'evento del clic su qualcosa come .box: prima, allora .box non è in grado di rilevare alcun clic?
più venerabile signore, il

Questo è parzialmente vero: se il tuo CSS contiene qualcosa come .box {pointer-events: none;} .box: before {pointer-events: auto;} l'unico elemento che supporta ancora gli eventi è p: before. Ricorda comunque che js ti restituirà l'elemento .box principale da .box: prima non vive in The DOM.
Fasoeu,

9

La mia risposta funzionerà per chiunque voglia fare clic su un'area definitiva della pagina. Questo ha funzionato per me sul mio assoluto posizionamento: dopo

Grazie a questo articolo , ho realizzato (con jQuery) che posso usare e.pageYe e.pageXinvece di preoccuparmi e.offsetY/Xe e.clientY/Xproblemi tra i browser.

Attraverso la mia prova ed errore, ho iniziato a utilizzare le coordinate del mouse clientX e clientY nell'oggetto evento jQuery. Queste coordinate mi hanno dato l'offset X e Y del mouse rispetto all'angolo in alto a sinistra della porta di visualizzazione del browser. Mentre stavo leggendo la Guida di riferimento di jQuery 1.4 di Karl Swedberg e Jonathan Chaffer, tuttavia, ho visto che si riferivano spesso alle coordinate pageX e pageY. Dopo aver verificato la documentazione aggiornata di jQuery, ho visto che queste erano le coordinate standardizzate da jQuery; e ho visto che mi davano l'offset X e Y del mouse rispetto all'intero documento (non solo alla porta di visualizzazione).

Mi è piaciuta questa event.pageYidea perché sarebbe sempre stata la stessa, in quanto era relativa al documento . Posso paragonarlo al mio elemento parent: after usando offset (), che restituisce anche la sua X e Y rispetto al documento.

Pertanto, posso trovare una gamma di regioni "cliccabili" sull'intera pagina che non cambia mai.


Ecco la mia demo su codepen .


o se troppo pigro per codepen, ecco il JS:

* Mi importava solo dei valori Y per il mio esempio.

var box = $('.box');
// clickable range - never changes
var max = box.offset().top + box.outerHeight();
var min = max - 30; // 30 is the height of the :after

var checkRange = function(y) {
  return (y >= min && y <= max);
}

box.click(function(e){
  if ( checkRange(e.pageY) ) {
    // do click action
    box.toggleClass('toggle');
  }
});

6

Questo funziona per me:

$('#element').click(function (e) {
        if (e.offsetX > e.target.offsetLeft) {
            // click on element
        }
         else{
           // click on ::before element
       }
});

6

Risposta breve:

L'ho fatto. Ho scritto una funzione per l'uso dinamico per tutte le piccole persone là fuori ...

Esempio funzionante che viene visualizzato nella pagina

Esempio di funzionamento registrazione sulla console

Risposta lunga:

... lo ha ancora fatto.

Mi ci è voluto un po 'per farlo, dal momento che un elemento psuedo non è davvero nella pagina. Mentre alcune delle risposte sopra funzionano in ALCUNI scenari, TUTTI non riescono a essere sia dinamici sia in uno scenario in cui un elemento ha dimensioni e posizione sia impreviste (come elementi posizionati assoluti che si sovrappongono a una parte dell'elemento padre). Il mio no.

Uso:

//some element selector and a click event...plain js works here too
$("div").click(function() {
    //returns an object {before: true/false, after: true/false}
    psuedoClick(this);

    //returns true/false
    psuedoClick(this).before;

    //returns true/false
    psuedoClick(this).after;

});

Come funziona:

Afferra le posizioni di altezza, larghezza, superiore e sinistra (in base alla posizione lontana dal bordo della finestra) dell'elemento principale e afferra le posizioni di altezza, larghezza, superiore e sinistra (basate sul bordo del contenitore principale ) e confronta tali valori per determinare dove si trova l'elemento psuedo sullo schermo.

Quindi confronta dove si trova il mouse. Finché il mouse si trova nell'intervallo di variabili appena creato, quindi restituisce true.

Nota:

È consigliabile posizionare l'elemento padre RELATIVO posizionato. Se hai un elemento psuedo posizionato in modo assoluto, questa funzione funzionerà solo se posizionata in base alle dimensioni del genitore (quindi il genitore deve essere relativo ... forse funzionerebbe anche appiccicoso o fisso ... Non lo so).

Codice:

function psuedoClick(parentElem) {

    var beforeClicked,
      afterClicked;

  var parentLeft = parseInt(parentElem.getBoundingClientRect().left, 10),
      parentTop = parseInt(parentElem.getBoundingClientRect().top, 10);

  var parentWidth = parseInt(window.getComputedStyle(parentElem).width, 10),
      parentHeight = parseInt(window.getComputedStyle(parentElem).height, 10);

  var before = window.getComputedStyle(parentElem, ':before');

  var beforeStart = parentLeft + (parseInt(before.getPropertyValue("left"), 10)),
      beforeEnd = beforeStart + parseInt(before.width, 10);

  var beforeYStart = parentTop + (parseInt(before.getPropertyValue("top"), 10)),
      beforeYEnd = beforeYStart + parseInt(before.height, 10);

  var after = window.getComputedStyle(parentElem, ':after');

  var afterStart = parentLeft + (parseInt(after.getPropertyValue("left"), 10)),
      afterEnd = afterStart + parseInt(after.width, 10);

  var afterYStart = parentTop + (parseInt(after.getPropertyValue("top"), 10)),
      afterYEnd = afterYStart + parseInt(after.height, 10);

  var mouseX = event.clientX,
      mouseY = event.clientY;

  beforeClicked = (mouseX >= beforeStart && mouseX <= beforeEnd && mouseY >= beforeYStart && mouseY <= beforeYEnd ? true : false);

  afterClicked = (mouseX >= afterStart && mouseX <= afterEnd && mouseY >= afterYStart && mouseY <= afterYEnd ? true : false);

  return {
    "before" : beforeClicked,
    "after"  : afterClicked

  };      

}

Supporto:

Non lo so .... sembra che sia stupido e gli piace restituire auto come valore calcolato a volte. SEMPRE FUNZIONA BENE IN TUTTI I BROWSER SE LE DIMENSIONI SONO IMPOSTATE NEI CSS. Quindi ... imposta la tua altezza e larghezza sui tuoi elementi psuedo e spostali solo con la parte superiore e sinistra. Vi consiglio di usarlo su cose su cui non state lavorando. Come un'animazione o qualcosa del genere. Chrome funziona ... come al solito.


eventviene passato attraverso una funzione del gestore eventi ogni volta che un evento viene attivato. Come fare clic o digitare. Quando usiamo la .click()funzione, stiamo aspettando l'evento click. Potremmo specificare e dire .click(function(e){...})di rendere l'evento, ema è anche accettabile usare solo event.

3
psEUdo, non psUEdo!
biziclop,

Il codice sopra non funziona, perché eventnon è definito.
Sebastian Zartner

@SebastianZartner - Event è una parola chiave. È quando l'utente fa qualcosa. Ho letteralmente spiegato questi due commenti sopra il tuo commento. Quando l'utente interagisce con la pagina, viene attivato un evento (nella maggior parte dei casi). Event è una parola chiave proveniente dal listener di eventi ".click ()". Se uno sviluppatore desidera utilizzare un nome diverso per l'evento, può impostarlo nel listener di eventi come ".click (e)", che è un modo più comune di vederlo. TUTTAVIA .... anche se ho un link che funziona sopra, includerò anche uno che è più ovvio e non accede alla console ma invece alla pagina per i bisognosi.

Avrei dovuto menzionare che non funziona in Firefox, perché non eventè definito. Funziona in Chrome e Edge, però.
Sebastian Zartner,

2

Aggiungi condizione nell'evento Click per limitare l'area selezionabile.

    $('#thing').click(function(e) {
       if (e.clientX > $(this).offset().left + 90 &&
             e.clientY < $(this).offset().top + 10) {
                 // action when clicking on after-element
                 // your code here
       }
     });

DEMO


1

Questa è la risposta modificata da Fasoeu con gli ultimi CSS3 e JS ES6

Demo modificata senza usare JQuery.

Esempio più breve di codice:

<p><span>Some text</span></p>
p {
    position: relative;
    pointer-events: none;
}
p::before {
    content: "";
    position: absolute;
    pointer-events: auto;
}
p span {
    display: contents;
    pointer-events: auto;
}
const all_p = Array.from(document.querySelectorAll('p'));

for (let p of all_p) {
    p.addEventListener("click", listener, false);
};

Spiegazione:

pointer-eventscontrolla il rilevamento di eventi, rimuovendo la ricezione di eventi dalla destinazione, ma continua a ricevere dagli pseudo-elementi rende possibile fare clic su ::beforee ::aftersaprai sempre cosa stai facendo clic sullo pseudo-elemento, tuttavia se hai ancora bisogno di fare clic, inserisci tutti i contenuti nell'elemento nidificato ( spanad esempio), ma poiché non vogliamo applicare altri stili, display: contents;diventa una soluzione molto utile e supportata dalla maggior parte dei browser . pointer-events: none;come già menzionato nel post originale anche ampiamente supportato .

Anche la parte JavaScript è ampiamente supportata Array.frome for...of, tuttavia, non è necessaria per l'uso nel codice.


0

Nessuna di queste risposte è affidabile e la mia non sarà molto più affidabile.

Avvertenze a parte, se entri nello scenario fortunato in cui l'elemento su cui stai cercando di fare clic non ha il riempimento (in modo tale che tutto lo spazio "interno" dell'elemento sia completamente coperto da sotto-elementi), allora tu può verificare la destinazione dell'evento click rispetto al contenitore stesso. Se corrisponde, significa che hai fatto clic su un elemento: before o: after.

Ovviamente questo non sarebbe fattibile con entrambi i tipi (prima e dopo), tuttavia l'ho implementato come correzione hack / speed e funziona molto bene, senza un sacco di controllo della posizione, che potrebbe essere impreciso a seconda di circa un milione di diversi fattori .


-2

No, ma puoi fare così

Nel file html aggiungi questa sezione

<div class="arrow">
</div>

In css puoi fare così

p div.arrow {
content: '';
position: absolute;
left:100%;
width: 10px;
height: 100%;
background-color: red;

} Spero che ti possa aiutare

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.