Обнаружение события щелчка только на псевдоэлементе

Мой код:

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

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

Смотрите эту скрипту: http://jsfiddle.net/ZWw3Z/5/

Я хотел бы вызвать событие click только на псевдоэлементе (красный бит). То есть, я не хочу, чтобы событие нажатия запускалось на синем бите.

Ответ 1

Это невозможно; псевдоэлементы вообще не являются частью DOM, поэтому вы не можете привязывать какие-либо события непосредственно к ним, вы можете привязываться только к их родительским элементам.

Если у вас должен быть обработчик кликов только в красной области, вы должны сделать дочерний элемент, например span, поместить его сразу после открытия тега <p>, применить стили к p span вместо p:before и привязать к нему.

Ответ 2

На самом деле, это возможно. Вы можете проверить, была ли позиция щелчка за пределами элемента, поскольку это произойдет, только если щелкнуть ::before или ::after.

В этом примере проверяется только элемент справа, но это должно работать в вашем случае.

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>

Ответ 3

В современных браузерах вы можете попробовать использовать свойство css-указателя-событий (но это приводит к невозможности обнаружить события мыши в родительском node):

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

Когда целью события является ваш элемент "p", вы знаете, что это ваш "p: before".

Если вам по-прежнему необходимо обнаружить события мыши на основном p, вы можете рассмотреть возможность изменения вашей структуры HTML. Вы можете добавить тег span и следующий стиль:

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

Цели события теперь представляют собой элементы "span" и "p: before".

Пример без jquery: http://jsfiddle.net/2nsptvcu/

Пример с jquery: http://jsfiddle.net/0vygmnnb/

Вот список браузеров, поддерживающих указатели-события: http://caniuse.com/#feat=pointer-events

Ответ 4

Мой ответ будет работать для тех, кто хочет нажать на определенную область страницы. Это работало для меня на моем абсолютно позиционированном: после

Благодаря этой статье , я понял (с jQuery), я могу использовать e.pageY и e.pageX вместо того, чтобы беспокоиться о проблемах e.offsetY/X и e.clientY/X между браузерами.

В ходе проб и ошибок я начал использовать координаты mouseX и clientY мыши в объекте события jQuery. Эти координаты дали мне смещение X и Y мыши относительно верхнего левого угла порта просмотра браузера. Однако, когда я читал справочник JQuery 1.4 от Karl Swedberg и Jonathan Chaffer, я видел, что они часто ссылались на координаты pageX и pageY. После проверки обновленной документации jQuery я увидел, что это координаты, стандартизированные jQuery; и я увидел, что они дали мне смещение X и Y мыши относительно всего документа (а не только порт представления).

Мне понравилась эта идея event.pageY, потому что она всегда была бы такой же, как она была относительно документа. Я могу сравнить его с моим: после родительского элемента с использованием offset(), который возвращает свои X и Y также относительно документа.

Поэтому я могу создать диапазон "кликабельной" области на всей странице, которая никогда не изменяется.


Здесь моя демонстрация на кодефене.


или слишком ленив для codepen, здесь JS:

* Я только заботился о значениях Y для моего примера.

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

Ответ 5

Это работает для меня:

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

Ответ 6

Короткий ответ:

Я это сделал. Я написал функцию для динамического использования для всех маленьких людей там...

Рабочий пример, который отображается на странице

Рабочий пример входа в консоль

Длинный ответ:

... все еще сделал это.

Это заняло у меня некоторое время, так как элемент psuedo на самом деле отсутствует на странице. Хотя некоторые из приведенных выше ответов работают в НЕКОТОРЫХ сценариях, они ВСЕ не могут быть как динамическими, так и работающими в сценарии, в котором элемент является неожиданным по размеру и положению (например, элементы с абсолютным позиционированием, перекрывающие часть родительского элемента). Мой нет.

Использование:

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

});

Как это устроено:

Он захватывает высоту, ширину, верхнюю и левую позиции (в зависимости от положения от края окна) родительского элемента и захватывает высоту, ширину, верхнюю и левую позиции (в зависимости от края родительского контейнера). ) и сравнивает эти значения, чтобы определить, где находится элемент psuedo на экране.

Затем он сравнивает, где находится мышь. Пока мышь находится во вновь созданном диапазоне переменных, она возвращает true.

Замечания:

Целесообразно расположить родительский элемент ОТНОСИТЕЛЬНО. Если у вас есть элемент psuedo с абсолютным позиционированием, эта функция будет работать только в том случае, если он позиционируется на основе родительских измерений (поэтому родительский элемент должен быть относительным... может быть, липкий или фиксированный будет работать тоже.... Я не знаю).

Код:

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

  };      

}

Служба поддержки:

Я не знаю.... похоже, что он тупой и любит иногда возвращать auto как вычисленное значение. ОЧЕНЬ РАБОТАЕТ В ВСЕХ БРАУЗЕРАХ, ЕСЛИ РАЗМЕРЫ УСТАНОВЛЕНЫ В CSS. Так что... установите свою высоту и ширину на элементах psuedo и перемещайте их только сверху и слева. Я рекомендую использовать это на вещах, с которыми у вас все в порядке, если вы не работаете. Как анимация или что-то. Хром работает... как обычно.

Ответ 7

Добавить условие в событии Click, чтобы ограничить область, на которую можно щелкнуть.

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

Ответ 8

Ни один из этих ответов не является надежным, и мой не будет намного более надежным.

Предостережения в сторону, если вы попадаете в счастливый сценарий, где элемент, который вы пытаетесь щелкнуть, не имеет прокладки (так что все "внутреннее" пространство элемента полностью покрывается подэлементами), то вы можете проверить цель события click против самого контейнера. Если он совпадает, это означает, что вы нажали элемент: before или: после.

Очевидно, это было бы невозможно в обоих типах (до и после), однако я реализовал его как исправление хака/скорости, и он работает очень хорошо, без кучи проверки позиции, что может быть неточным в зависимости от миллионов различных факторов.

Ответ 9

Это отредактированный ответ Fasoeu с последними версиями CSS3 и JS ES6

Отредактировано демо без использования JQuery.

Кратчайший пример кода:

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

Объяснение:

pointer-events контролирует обнаружение событий, удаляя принимающие события из цели, но продолжая получать от псевдоэлементов, позволяя нажимать ::before и ::after, и вы всегда будете знать, что нажимаете на псевдоэлементе, однако, если вы по-прежнему нужно нажимать, вы помещаете все содержимое во вложенный элемент (например, span), но поскольку мы не хотим применять какие-либо дополнительные стили, display: contents; становится очень удобным решением, и оно поддерживается большинством браузеров. pointer-events: none;, как уже упоминалось в оригинальном сообщении, также широко поддерживается.

В части JavaScript также широко используются Array.from и for...of, однако их не нужно использовать в коде.

Ответ 10

Нет, но вы можете сделать это

В html файле добавьте этот раздел

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

В css вы можете сделать это

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

} Надеюсь, это поможет вам.