仅检测伪元素上的单击事件

时间:2011-09-19 23:07:28

标签: javascript jquery css

我的代码是:

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事件。也就是说,我不希望在蓝色位上触发click事件。

9 个答案:

答案 0 :(得分:200)

这是不可能的;伪元素根本不是DOM的一部分,所以你不能将任何事件直接绑定到它们,你只能绑定到它们的父元素。

如果您必须只在红色区域上设置点击处理程序,则必须创建一个子元素,如span,将其放在打开的<p>标记之后,将样式应用于{{ 1}}而不是p span,并绑定到它。

答案 1 :(得分:121)

实际上,这是可能的。您可以检查点击的位置是否在元素之外,因为这只会在点击::before::after时发生。

此示例仅检查右侧的元素,但这应该适用于您的情况。

&#13;
&#13;
span = document.querySelector('span');

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

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

JSFiddle

答案 2 :(得分:60)

现代浏览器上,您可以尝试使用pointer-events css属性(但这会导致无法检测父节点上的鼠标事件):

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

当事件目标是你的&#34; p&#34;元素,你知道它是你的&#34; p:之前&#34;。

如果仍需要检测主p上的鼠标事件,可以考虑修改HTML结构的可能性。您可以添加 span 标记和以下样式:

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

事件目标现在都是&#34; span&#34; &#34; p:之前&#34;元件。

没有jquery的示例:http://jsfiddle.net/2nsptvcu/

jquery示例:http://jsfiddle.net/0vygmnnb/

以下是支持指针事件的浏览器列表:http://caniuse.com/#feat=pointer-events

答案 3 :(得分:7)

我的回答适用于想要点击页面最终区域的任何人。这对我来说非常有用绝对定位:在

之后

感谢这个article,我意识到(使用jQuery)我可以使用e.pageYe.pageX而不是担心浏览器之间出现e.offsetY/Xe.clientY/X问题

  

通过我的试验和错误,我开始在jQuery事件对象中使用clientX和clientY鼠标坐标。这些坐标给出了鼠标相对于浏览器视图端口左上角的X和Y偏移量。当我阅读Karl Swedberg和Jonathan Chaffer的jQuery 1.4参考指南时,我看到他们经常提到pageX和pageY坐标。检查更新的jQuery文档后,我看到这些是jQuery标准化的坐标;并且,我看到他们给了我相对于整个文档(而不仅仅是视口)鼠标的X和Y偏移量。

我喜欢这个event.pageY想法,因为它总是相同的,因为相对于文档。我可以将它与我的:在使用offset()之后的父元素进行比较,它返回其相对于文档的X和Y.

因此,我可以提出一系列可点击的&#34;整个页面上永远不会改变的区域。

这是我的demo on codepen

或者如果对于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');
  }
});

答案 4 :(得分:3)

这对我有用:

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

答案 5 :(得分:3)

简答:

我做到了。 我为所有那些小人物写了一个动态使用函数...

Working example which displays on the page

Working example logging to the console

长答案:

......仍然做到了。

我花了一段时间才这样做,因为页面上并没有真正的伪元素。虽然上面的一些答案在某些情况下有效,但它们都不能同时处于动态状态,并且在元素大小和位置都是意外的情况下工作(例如绝对定位元素覆盖父元素的一部分)。我没有。

<强>用法:

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

注意:

明智地将父元素RELATIVE定位。如果你有一个绝对定位的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中设置了尺寸,那么它可以在所有浏览器中工作。所以...在你的伪元素上设置你的高度和宽度,只用顶部和左边移动它们。我推荐在你可以使用它的东西上使用它。像动画或其他东西。 Chrome像往常一样工作。

答案 6 :(得分:1)

在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

答案 7 :(得分:0)

Fasoeu使用最新的CSS3和JS ES6编辑了答案

Edited demo,而不使用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;会变成非常方便的解决方案,most browsers支持。 pointer-events: none;也已在原始帖子中广泛提及,supported

JavaScript部分还使用了受广泛支持的Array.fromfor...of,但是在代码中不必使用它们。

答案 8 :(得分:-2)

不,但你可以这样做

在html文件中添加此部分

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

在CSS中你可以这样做

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

} 希望它能帮到你