web-dev-qa-db-fra.com

Détecter uniquement l'événement click sur le pseudo-élément

Mon code est:

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

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

S'il vous plaît voir ce violon: http://jsfiddle.net/ZWw3Z/5/

Je voudrais déclencher un événement de clic uniquement sur le pseudo-élément (le bit rouge). C'est-à-dire que je ne veux pas que l'événement click soit déclenché sur le bit bleu.

197
Randomblue

Ce n'est pas possible; Les pseudo-éléments ne font pas du tout partie du DOM; vous ne pouvez donc lier aucun événement directement à eux. Vous pouvez uniquement vous lier à leurs éléments parents.

Si vous devez avoir un gestionnaire de clics uniquement sur la région rouge, vous devez créer un élément enfant, tel qu'un span, placez-le juste après la balise <p> d'ouverture, appliquez les styles à p span au lieu de p:before, et s'y lier.

205
BoltClock

En fait, c'est possible. Vous pouvez vérifier si la position cliquée était en dehors de l'élément, car cela ne se produira que si vous avez cliqué sur ::before ou ::after.

Cet exemple ne vérifie que l'élément à droite mais cela devrait fonctionner dans votre cas.

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

124
Linus Unnebäck

Sur les navigateurs modernes , vous pouvez essayer avec la propriété css pointer-events (mais il est impossible de détecter les événements de souris sur le nœud parent):

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;
}

Lorsque la cible de l'événement est votre élément "p", vous savez que c'est votre "p: before".

Si vous avez toujours besoin de détecter des événements de souris sur le p principal, vous pouvez envisager la possibilité de modifier votre structure HTML. Vous pouvez ajouter une balise span span et le style suivant:

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

Les cibles d'événement sont maintenant les éléments "span" et "p: before".

Exemple sans jquery: http://jsfiddle.net/2nsptvcu/

Exemple avec jquery: http://jsfiddle.net/0vygmnnb/

Voici la liste des navigateurs supportant les événements de pointeur: http://caniuse.com/#feat=pointer-events

64
Fasoeu

Ma réponse fonctionnera pour tous ceux qui souhaitent cliquer sur une zone définitive de la page. Cela a fonctionné pour moi sur mon position absolue: après

Grâce à cela article , j'ai réalisé (avec jQuery) que je peux utiliser le problème e.pageY et e.pageX au lieu de m'inquiéter pour e.offsetY/X et e.clientY/X entre navigateurs .

Lors d'essais et d'erreurs, j'ai commencé à utiliser les coordonnées clientX et clientY dans l'objet événement jQuery. Ces coordonnées m'ont donné les décalages X et Y de la souris par rapport au coin supérieur gauche du port d'affichage du navigateur. En lisant le Guide de référence jQuery 1.4 de Karl Swedberg et Jonathan Chaffer, j'ai toutefois constaté qu'ils se référaient souvent aux coordonnées pageX et pageY. Après avoir vérifié la documentation mise à jour de jQuery, j'ai constaté qu'il s'agissait des coordonnées normalisées par jQuery; et, j'ai vu qu'ils m'avaient donné les décalages X et Y de la souris par rapport au document entier (pas seulement le port d'affichage).

J'ai bien aimé cette idée event.pageY parce que ce serait toujours la même chose, telle qu'elle était par rapport au document . Je peux le comparer à l'élément parent de mon: after en utilisant offset (), qui renvoie ses X et Y également par rapport au document.

Par conséquent, je peux proposer une gamme de régions "cliquables" sur la page entière qui ne change jamais.


Voici mon démo sur codepen .


ou si vous êtes trop paresseux pour codepen, voici le JS:

* Je me souciais seulement des valeurs Y pour mon exemple.

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');
  }
});
8
amurrell

Cela fonctionne pour moi:

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

Réponse courte:

Je l'ai fait. J'ai écrit une fonction d'utilisation dynamique pour toutes les petites gens là-bas ...

Exemple de travail qui s'affiche sur la page

Exemple de travail se connectant à la console

Réponse longue:

... l'a encore fait.

Il m'a fallu un certain temps pour le faire, car un élément psuedo n'est pas vraiment sur la page. Certaines des réponses ci-dessus fonctionnent dans CERTAINS scénarios, mais elles échouent TOUTES être dynamiques et dans un scénario dans lequel la taille et la position d’un élément sont inattendues (telles que des éléments positionnés en absolu superposant une partie de l’élément parent). Le mien non.

Utilisation:

//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;

});

Comment ça marche:

Il saisit les positions hauteur, largeur, haut et gauche (en fonction de la position éloignée du bord de la fenêtre) de l'élément parent et saisit les positions hauteur, largeur, haut et gauche (en fonction du bord du conteneur parent). ) et compare ces valeurs pour déterminer où se trouve l'élément psuedo à l'écran.

Il compare ensuite où se trouve la souris. Tant que la souris se trouve dans la plage de variables nouvellement créée, elle renvoie true.

Remarque:

Il est sage de positionner l'élément parent RELATIVE. Si vous avez un élément psuedo à positionnement absolu, cette fonction ne fonctionnera que si elle est positionnée en fonction des dimensions du parent (le parent doit donc être relatif ... peut-être qu'il soit collant ou corrigé fonctionnerait aussi ... je ne sais pas).

Code:

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

  };      

}

Assistance:

Je ne sais pas .... on dirait que c'est idiot et aime parfois retourner auto comme valeur calculée. Il semble que tous les navigateurs fonctionnent correctement si les dimensions sont définies en CSS. Alors ... définissez votre hauteur et votre largeur sur vos éléments psuedo et ne les déplacez qu'en haut et à gauche. Je recommande de l'utiliser sur des choses qui ne vous dérangent pas. Comme une animation ou quelque chose. Chrome fonctionne ... comme d'habitude.

4
Aaron Loften

Ajoutez une condition dans l'événement Click pour restreindre la zone cliquable.

    $('#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
       }
     });

DÉMO

1
Abdennour TOUMI

Aucune de ces réponses n'est fiable et la mienne ne sera pas beaucoup plus fiable.

Mises en garde de côté, si vous entrez dans le scénario chanceux où l’élément sur lequel vous essayez de cliquer n’a pas de rembourrage (de sorte que tout l’espace "intérieur" de l’élément soit complètement recouvert par des sous-éléments), peut vérifier la cible de l'événement click par rapport au conteneur lui-même. Si cela correspond, cela signifie que vous avez cliqué sur un élément: avant ou: après.

Évidemment, cela ne serait pas réalisable avec les deux types (avant et après), mais je l’ai implémenté comme solution de piratage/rapidité et cela fonctionne très bien, sans une série de vérifications de position, ce qui peut être inexact en fonction d’un million de facteurs différents. .

0
dudewad