Javascript 只检测伪元素上的点击事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7478336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 02:26:06  来源:igfitidea点击:

Only detect click event on pseudo-element

javascriptjquerycss

提问by Randomblue

My code is:

我的代码是:

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

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

Please see this fiddle: http://jsfiddle.net/ZWw3Z/5/

请看这个小提琴:http: //jsfiddle.net/ZWw3Z/5/

I would like to trigger a click event only on the pseudo-element (the red bit). That is, I don't want the click event to be triggered on the blue bit.

我只想在伪元素(红色位)上触发点击事件。也就是说,我不希望在蓝色位上触发点击事件。

回答by BoltClock

This is not possible; pseudo-elements are not part of the DOM at all so you can't bind any events directly to them, you can only bind to their parent elements.

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

If you must have a click handler on the red region only, you have to make a child element, like a span, place it right after the opening <p>tag, apply styles to p spaninstead of p:before, and bind to it.

如果你必须只在红色区域有一个点击处理程序,你必须创建一个子元素,比如 a span,将它放在开始<p>标签之后,将样式应用到p span而不是p:before,并绑定到它。

回答by Linus Unneb?ck

Actually, it is possible. You can check if the clicked position was outside of the element, since this will only happen if ::beforeor ::afterwas clicked.

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

This example only checks the element to the right but that should work in your case.

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

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

JSFiddle

回答by Fasoeu

On modern browsersyou can try with the pointer-events css property (but it leads to the impossibility to detect mouse events on the parent node):

现代浏览器上,您可以尝试使用 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;
}

When the event target is your "p" element, you know it is your "p:before".

当事件目标是您的“p”元素时,您就知道它是您的“p:before”。

If you still need to detect mouse events on the main p, you may consider the possibility to modify your HTML structure. You can add a spantag and the following style:

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

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

The event targets are now both the "span" and the "p:before" elements.

事件目标现在既是“span”又是“p:before”元素。

Example without jquery: http://jsfiddle.net/2nsptvcu/

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

Example with jquery: http://jsfiddle.net/0vygmnnb/

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

Here is the list of browsers supporting pointer-events: http://caniuse.com/#feat=pointer-events

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

回答by amurrell

My answer will work for anyone wanting to click a definitive area of the page. This worked for me on my absolutely-positioned :after

我的答案适用于想要单击页面确定区域的任何人。这对我的绝对定位对我有用 :after

Thanks to this article, I realized (with jQuery) I can use e.pageYand e.pageXinstead of worrying about e.offsetY/Xand e.clientY/Xissue between browsers.

由于这个文章,我才意识到(用jQuery)我可以用e.pageYe.pageX而不必担心e.offsetY/Xe.clientY/X浏览器之间的问题。

Through my trial and error, I started to use the clientX and clientY mouse coordinates in the jQuery event object. These coordinates gave me the X and Y offset of the mouse relative to the top-left corner of the browser's view port. As I was reading the jQuery 1.4 Reference Guide by Karl Swedberg and Jonathan Chaffer, however, I saw that they often referred to the pageX and pageY coordinates. After checking the updated jQuery documentation, I saw that these were the coordinates standardized by jQuery; and, I saw that they gave me the X and Y offset of the mouse relative to the entire document (not just the view port).

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

I liked this event.pageYidea because it would always be the same, as it was relative to the document. I can compare it to my :after's parent element using offset(), which returns its X and Y also relative to the document.

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

Therefore, I can come up with a range of "clickable" region on the entire page that never changes.

因此,我可以在整个页面上提出一系列永不改变的“可点击”区域。



Here's my demo on codepen.

这是我在 codepen 上演示



or if too lazy for codepen, here's the JS:

或者如果对 codepen 太懒了,这里是 JS:

* I only cared about the Y values for my example.

* 我只关心我的例子的 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');
  }
});

回答by Rick

This works for me:

这对我有用:

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

回答by Rick

Short Answer:

简答:

I did it. I wrote a function for dynamic usage for all the little people out there...

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

Working example which displays on the page

显示在页面上的工作示例

Working example logging to the console

登录到控制台的工作示例

Long Answer:

长答案:

...Still did it.

……还是做了。

It took me awhile to do it, since a psuedo element is not really on the page. While some of the answers above work in SOME scenarios, they ALL fail to be both dynamic and work in a scenario in which an element is both unexpected in size and position(such as absolute positioned elements overlaying a portion of the parent element). Mine does not.

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

Usage:

用法:

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

});

How it works:

这个怎么运作:

It grabs the height, width, top, and left positions(based on the position away from the edge of the window) of the parent element and grabs the height, width, top, and left positions(based on the edge of the parent container) and compares those values to determine where the psuedo element is on the screen.

它抓取父元素的高度、宽度、顶部和左侧位置(基于远离窗口边缘的位置)并抓取高度、宽度、顶部和左侧位置(基于父容器的边缘) ) 并比较这些值以确定伪元素在屏幕上的位置。

It then compares where the mouse is. As long as the mouse is in the newly created variable range then it returns true.

然后比较鼠标的位置。只要鼠标在新创建的变量范围内,它就会返回 true。

Note:

笔记:

It is wise to make the parent element RELATIVE positioned. If you have an absolute positioned psuedo element, this function will only work if it is positioned based on the parent's dimensions(so the parent has to be relative...maybe sticky or fixed would work too....I dont know).

使父元素 RELATIVE 定位是明智的。如果你有一个绝对定位的伪元素,这个函数只有在基于父元素的尺寸定位时才有效(所以父元素必须是相对的......也许粘性或固定也可以工作......我不知道)。

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

  };      

}

Support:

支持:

I dont know....it looks like ie is dumb and likes to return auto as a computed value sometimes. IT SEEMS TO WORK WELL IN ALL BROWSERS IF DIMENSIONS ARE SET IN CSS. So...set your height and width on your psuedo elements and only move them with top and left. I recommend using it on things that you are okay with it not working on. Like an animation or something. Chrome works...as usual.

我不知道....它看起来像 ie 是愚蠢的,有时喜欢将 auto 作为计算值返回。如果尺寸在 CSS 中设置,它似乎在所有浏览器中都能正常工作。所以......在你的伪元素上设置你的高度和宽度,并且只在顶部和左侧移动它们。我建议将它用于您认为它不起作用的事情上。比如动画什么的。Chrome 工作......像往常一样。

回答by Abdennour TOUMI

Add condition in Click event to restrict the clickable area .

在 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

演示

回答by XCanG

This is edited answer by Fasoeuwith latest CSS3 and JS ES6

这是Fasoeu用最新的 CSS3 和 JS ES6编辑的答案

Edited demowithout using JQuery.

不使用 JQuery编辑演示

Shortest example of code:

最短的代码示例:

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

Explanation:

解释:

pointer-eventscontrol detection of events, removing receiving events from target, but keep receiving from pseudo-elements make possible to click on ::beforeand ::afterand you will always know what you are clicking on pseudo-element, however if you still need to click, you put all content in nested element (spanin example), but because we don't want to apply any additional styles, display: contents;become very handy solution and it supported by most browsers. pointer-events: none;as already mentioned in original post also widely supported.

pointer-events控制事件检测,从目标中删除接收事件,但继续从伪元素接收使点击成为可能::before::after并且您将始终知道您在伪元素上点击了什么,但是如果您仍然需要点击,则将所有内容在嵌套元素中(span在示例中),但因为我们不想应用任何额外的样式,display: contents;成为非常方便的解决方案,并且大多数浏览器都支持它。pointer-events: none;正如原帖中已经提到的,也得到了广泛支持

The JavaScript part also used widely supported Array.fromand for...of, however they are not necessary to use in code.

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

回答by dudewad

None of these answers are reliable, and mine wont be much more reliable.

这些答案都不可靠,我的也不可靠。

Caveats aside, if you do get into the lucky scenario where the element you're trying to have clicked doesn't have padding (such that all of the "inner" space of the element is completely covered by sub-elements), then you can check the target of the click event against the container itself. If it matches, that means you've clicked a :before or :after element.

除了警告之外,如果您确实遇到了您尝试单击的元素没有填充的幸运场景(这样元素的所有“内部”空间都被子元素完全覆盖),那么您可以根据容器本身检查单击事件的目标。如果匹配,则意味着您单击了 :before 或 :after 元素。

Obviously this would not be feasible with both types (before and after) however I have implemented it as a hack/speed fix and it is working very well, without a bunch of position checking, which may be inaccurate depending on about a million different factors.

显然这对于​​两种类型(之前和之后)都是不可行的,但是我已经将它实现为一个黑客/速度修复并且它运行得很好,没有一堆位置检查,这可能不准确,这取决于大约一百万个不同的因素.

回答by Gopal Bogati

No,but you can do like this

不,但你可以这样做

In html file add this section

在 html 文件中添加此部分

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

In css you can do like this

在 css 中你可以这样做

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

} Hope it will help you

希望它会帮助你