의사 요소에서 클릭 이벤트 만 감지


213

내 코드는 다음과 같습니다

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/

의사 요소 (빨간색 비트)에서만 클릭 이벤트를 트리거하고 싶습니다. 즉, 클릭 이벤트가 파란색 비트에서 트리거되는 것을 원하지 않습니다.


1
클릭 된 위치를 확인하는 것은 어떻습니까? stackoverflow.com/questions/3234977/…

이전에 게시 한 솔루션을 여기에서 읽으 십시오 .
Amr

여기에 좋은 해결 방법이있을 것 입니다.
레자 마문

답변:


218

이건 불가능 해; 의사 요소는 DOM의 일부가 아니므로 이벤트를 직접 바인딩 할 수 없으며 부모 요소에만 바인딩 할 수 있습니다.

빨간색 영역에만 클릭 핸들러가 있어야하는 경우, 같은 하위 요소를 span시작 <p>태그 바로 뒤에 배치하고 스타일 p span대신 스타일을 적용한 다음 p:before바인딩해야합니다.


108
현대 브라우저에서 이것은 pointer-events요소 자체와 의사 요소에 대해 다른 값 으로 가능할 것 같습니다 : jsfiddle.net/ZWw3Z/70
Ilya Streltsyn

5
@Ilya Streltsyn 놀라운- '올바른'답변이 아니라 (요소를 클릭해야 할 경우 작동하지 않음) div의 '닫기 버튼'에 대해 훌륭하게 작동합니다
RozzA

pointer-eventsIlya가 게시 한 jsfiddel에 따르면 IE9에 대한 트릭을 수행하지 않는 것으로 보입니다.
user393274

@ user393274 : IE9는 SVG 외부의 포인터 이벤트를 지원하지 않습니다.
BoltClock

1
@theyuv 아니오, 해당 페이지에서 링크의 왼쪽과 오른쪽 모두에서 전체 라인을 클릭 할 수 있습니다. 링크 자체에만 다른 클릭 핸들러가 있으므로 클릭하면 폴딩 / 폴딩 하위 트리가 트리거되지 않습니다.
Ilya Streltsyn

131

실제로 가능합니다. 클릭 한 위치가 요소 외부에 있는지 확인할 수 있습니다 . ::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>

JSFiddle


1
그것은 나를 위해 작동하지 않습니다, 내가 클릭하면 텍스트가 강조 표시됩니다. 중요하다면 Firefox를 사용하십시오.
Flater

2
: 파이어 폭스에 대한 jsfiddle.net/wC2p7/16 . 중첩 요소로 작업하는 경우 중첩 오프셋을 적절하게 계산해야 할 수도 있습니다 (예 : jQuery : $ (e.target) .offset (). left)
bebbi

1
멋진 남자 고마워요. 그러나 Firefox 및 기타 표준 호환 브라우저에서 마우스 오버 여부를 테스트 :after하기 위해 if (e.clientX > span.offsetLeft + span.offsetHeight)이러한 브라우저에 e.offsetX속성 이 없는지 확인 해야합니다 . 바이올린 : jsfiddle.net/Noitidart/wC2p7/18
Noitidart

5
jQuery가 지원하기로 결정했다면 더 시원 할 것입니다. $('a:after').on('click', fn)그러나 나는 그것이 실제로 일어나는 것을 보지 못합니다 : p
Linus Unnebäck

25
요소 내부에 ::before또는 ::after요소가 있으면 실제로 작동하지 않습니다 .
laconbass

74

최신 브라우저 당신은 포인터 이벤트 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;
}

이벤트 대상이 "p"요소 인 경우 "p : before"임을 알 수 있습니다.

여전히 메인 p에서 마우스 이벤트를 감지해야하는 경우 HTML 구조를 수정할 가능성을 고려할 수 있습니다. 스팬 태그와 다음 스타일을 추가 할 수 있습니다 .

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


부모 노드가 왜인지 모르겠습니다. .box : before와 같은 클릭 이벤트를 클릭하면 .box가 클릭을 감지 할 수 없다는 말입니까?
가장 존경받는 선생님

CSS에 .box {pointer-events : none;} .box : before {pointer-events : auto;}와 같은 것이 포함되어 있으면 여전히 이벤트를 지원하는 유일한 요소는 p : before입니다. 어쨌든 js는 .box : before가 실제로 DOM에 살지 않기 때문에 기본 .box 요소를 다시 제공한다는 것을 기억하십시오.
Fasoeu

9

내 답변은 페이지의 결정적인 영역을 클릭하려는 사람에게 효과적입니다. 이것은 내 절대 위치 에 대해 나를 위해 일했습니다 : after

기사 덕분에 (jQuery를 사용 e.pageY하여 ) 브라우저간에 e.pageX걱정 e.offsetY/X하고 e.clientY/X문제 대신 사용할 수 있음을 깨달았습니다 .

시행 착오를 통해 jQuery 이벤트 객체에서 clientX 및 clientY 마우스 좌표를 사용하기 시작했습니다. 이 좌표는 브라우저보기 포트의 왼쪽 상단 모서리를 기준으로 마우스의 X 및 Y 오프셋을 나타냅니다. 그러나 Karl Swedberg와 Jonathan Chaffer의 jQuery 1.4 Reference Guide를 읽을 때 종종 pageX 및 pageY 좌표를 참조하는 것을 보았습니다. 업데이트 된 jQuery 문서를 확인한 후 이것이 jQuery에 의해 표준화 된 좌표임을 알 수있었습니다. 그리고 그들은 그들이 전체 문서 (보기 포트뿐만 아니라)에 대해 마우스의 X 및 Y 오프셋을 나에게주는 것을 보았습니다.

event.pageY아이디어 는 문서 와 관련 이 있기 때문에 항상 동일하기 때문에 좋아했습니다 . 오프셋을 사용하여 내 : after의 부모 요소와 비교할 수 있습니다 .offset ()을 사용하면 문서와 관련된 X 및 Y도 반환합니다.

따라서 전체 페이지에서 변하지 않는 "클릭 가능한"영역 범위를 만들 수 있습니다.


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

6

이것은 나를 위해 작동합니다 :

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

  };      

}

지원하다:

나는 모른다 .... 그것은 바보처럼 보이고 때로는 계산 된 값으로 자동을 반환하는 것을 좋아합니다. 치수가 CSS로 설정된 경우 모든 브라우저에서 잘 작동하는 것으로 보입니다. 따라서 ... psuedo 요소의 높이와 너비를 설정하고 위쪽과 왼쪽으로 만 이동하십시오. 나는 그것이 작동하지 않는 괜찮은 것들에 그것을 사용하는 것이 좋습니다. 애니메이션이나 무언가처럼. Chrome은 평소와 같이 작동합니다.


event이벤트가 발생할 때마다 이벤트 핸들러 함수를 통해 전달됩니다. 클릭하거나 입력하는 것과 같습니다. .click()함수 를 사용할 때 클릭 이벤트를 기다리고 있습니다. 우리는 .click(function(e){...})이벤트를 지정하고 말할 수 e있지만 그냥 사용하는 것도 허용됩니다 event.

3
psUEdo가 아니라 psEUdo!
biziclop

event정의되지 않았 으므로 위의 코드가 작동하지 않습니다 .
Sebastian Zartner

@SebastianZartner-이벤트는 키워드입니다. 사용자가 무언가를 할 때입니다. 나는 말 그대로 당신의 의견 위에이 두 의견을 설명했습니다. 사용자가 페이지와 상호 작용하면 이벤트가 발생합니다 (대부분의 경우). 이벤트는 이벤트 리스너 ".click ()"에서 나오는 키워드입니다. 개발자가 이벤트에 다른 이름을 사용하려면 ".click (e)"와 같은 이벤트 리스너에서 이벤트를 설정하여보다 일반적인 방법으로 볼 수 있습니다. 그러나 .... 위에서 작동하는 링크가 있지만 더 명확하고 콘솔에 로그인하지 않고 가난한 사람들을위한 페이지에 링크를 포함시킵니다.

event정의되지 않았기 때문에 Firefox에서는 작동하지 않는다고 언급해야합니다 . 그러나 Chrome과 Edge에서 작동합니다.
Sebastian Zartner

2

클릭 가능 영역을 제한하려면 클릭 이벤트에 조건을 추가하십시오.

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

데모


1

이것은 최신 CSS3 및 JS ES6 로 Fasoeu 가 편집 한 답변입니다.

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;원래 게시물에서 이미 언급했듯이 널리 지원됩니다 .

자바 스크립트 부분도 광범위하게 지원 사용 Array.from하고 for...of그들이 코드를 사용할 필요가 없습니다 그러나.


0

이 답변들 중 어느 것도 신뢰할 수 없으며 내 것이 훨씬 더 신뢰할 수는 없습니다.

클릭하려는 요소에 패딩이없는 운이 좋은 시나리오 (예 : 요소의 모든 "내부"공간이 하위 요소로 완전히 채워져있는 경우)에주의해야합니다. 컨테이너 자체에 대해 click 이벤트의 대상을 확인할 수 있습니다. 일치하면 : before 또는 : after 요소를 클릭했음을 의미합니다.

분명히 이것은 두 가지 유형 (전후)으로 실현 가능하지는 않지만 해킹 / 속도 수정으로 구현했으며 위치 확인없이 매우 잘 작동하며 약 백만 가지 요소에 따라 부정확 할 수 있습니다 .


-2

아니요,하지만 이렇게 할 수 있습니다

html 파일에서이 섹션을 추가하십시오

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

CSS에서는 다음과 같이 할 수 있습니다

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

} 도움이되기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.