Chỉ phát hiện sự kiện nhấp chuột trên phần tử giả


213

Mã của tôi là:

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

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

Vui lòng xem fiddle này: http://jsfiddle.net/ZWw3Z/5/

Tôi muốn kích hoạt một sự kiện nhấp chuột chỉ trên phần tử giả (bit màu đỏ). Đó là, tôi không muốn sự kiện nhấp được kích hoạt trên bit màu xanh.


1
Làm thế nào về việc kiểm tra nhấp chuột pos? stackoverflow.com/questions/3234977/NH

Xin vui lòng đọc giải pháp được đăng trước đây của tôi ở đây .
Amr

Có thể là một cách giải quyết tốt TẠI ĐÂY .
Reza Mamun

Câu trả lời:


218

Điều này là không thể; các phần tử giả hoàn toàn không phải là một phần của DOM vì vậy bạn không thể liên kết trực tiếp bất kỳ sự kiện nào với chúng, bạn chỉ có thể liên kết với các phần tử cha của chúng.

Nếu bạn phải chỉ có một trình xử lý nhấp chuột trên vùng màu đỏ, bạn phải tạo một phần tử con, như một span, đặt nó ngay sau <p>thẻ mở , áp dụng các kiểu p spanthay vì p:beforevà liên kết với nó.


108
Dường như trong các trình duyệt hiện đại, điều này là có thể với các pointer-eventsgiá trị khác nhau cho chính phần tử và phần tử giả của nó: jsfiddle.net/ZWw3Z/70
Ilya Streltsyn

5
@Ilya Streltsyn tuyệt vời - không phải là câu trả lời 'chính xác' (sẽ không hoạt động nếu bạn cũng cần nhấp vào phần tử) nhưng hoạt động tuyệt vời cho một 'nút đóng' trên divs
RozzA

pointer-eventskhông xuất hiện để thực hiện thủ thuật cho IE9, theo jsfiddel mà Ilya đã đăng.
dùng393274

@ user393274: IE9 không hỗ trợ các sự kiện con trỏ bên ngoài SVG.
BoltClock

1
@theyuv không, trên trang đó toàn bộ dòng có thể nhấp, cả bên trái và bên phải từ liên kết. Chỉ bản thân liên kết mới có trình xử lý nhấp chuột khác nhau, vì vậy nhấp vào liên kết đó sẽ không kích hoạt tính năng gập / mở ra cây con.
Ilya Streltsyn

131

Trên thực tế, nó là có thể. Bạn có thể kiểm tra xem vị trí được nhấp có nằm ngoài phần tử hay không, vì điều này sẽ chỉ xảy ra nếu ::beforehoặc ::afterđược nhấp.

Ví dụ này chỉ kiểm tra phần tử bên phải nhưng nó sẽ hoạt động trong trường hợp của bạn.

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
Nó không hoạt động đối với tôi, văn bản được tô sáng khi tôi nhấp vào. Sử dụng Firefox, nếu có vấn đề (không nên).
Flater

2
cho firefox: jsfiddle.net/wC2p7/16 . Nếu làm việc với các phần tử lồng nhau, bạn có thể cần tính toán các phần tử lồng nhau cho phù hợp (ví dụ: jQuery: $ (e.target) .offset (). Left)
bebbi

1
Người đàn ông tuyệt vời cảm ơn, nó hoạt động. Nhưng trong Firefox và các trình duyệt tuân thủ tiêu chuẩn khác, để kiểm tra xem :afterbạn có phải kiểm tra chuột không if (e.clientX > span.offsetLeft + span.offsetHeight)vì các trình duyệt này không có thuộc e.offsetXtính. Fiddle: jsfiddle.net/Noitidart/wC2p7/18
Noitidart

5
Thậm chí sẽ tuyệt hơn nếu jQuery quyết định hỗ trợ $('a:after').on('click', fn)nhưng tôi thực sự không thấy điều đó xảy ra: p
Linus Unnebäck

25
Điều này thực sự sẽ không hoạt động nếu ::beforehoặc ::afterđược định vị bên trong phần tử.
laconbass

74

Trên các trình duyệt hiện đại, bạn có thể thử với thuộc tính css con trỏ sự kiện (nhưng nó dẫn đến việc không thể phát hiện các sự kiện chuột trên nút cha):

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

Khi mục tiêu sự kiện là yếu tố "p" của bạn, bạn biết đó là "p: trước" của bạn.

Nếu bạn vẫn cần phát hiện các sự kiện chuột trên p chính, bạn có thể xem xét khả năng sửa đổi cấu trúc HTML của mình. Bạn có thể thêm thẻ span và kiểu sau:

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

Các mục tiêu sự kiện hiện là cả hai phần tử "span" và "p: before".

Ví dụ không có jquery: http://jsfiddle.net/2nsptvcu/

Ví dụ với jquery: http://jsfiddle.net/0vygmnnb/

Dưới đây là danh sách các trình duyệt hỗ trợ các sự kiện con trỏ: http://caniuse.com/#feat=pulum-events


Tôi không biết tại sao nút cha là. Bạn có nói rằng nếu tôi là sự kiện nhấp chuột vào một cái gì đó như .box: trước đó, thì .box không thể phát hiện bất kỳ nhấp chuột nào không?
đáng kính nhất thưa ngài

Điều đó đúng một phần: nếu CSS của bạn chứa một cái gì đó như .box {con trỏ sự kiện: none;} .box: trước {con trỏ sự kiện: auto;} thì phần tử duy nhất vẫn hỗ trợ các sự kiện là p: trước. Dù sao, hãy nhớ rằng js sẽ trả lại cho bạn phần tử .box chính kể từ .box: trước khi không thực sự sống trong DOM.
Fasoeu

9

Câu trả lời của tôi sẽ hoạt động cho bất cứ ai muốn nhấp vào một khu vực dứt khoát của trang. Điều này làm việc cho tôi trên vị trí hoàn toàn của tôi : sau

Nhờ bài viết này , tôi nhận ra (với jQuery) tôi có thể sử dụng e.pageYe.pageXthay vì lo lắng e.offsetY/Xe.clientY/Xvấn đề giữa các trình duyệt.

Thông qua bản dùng thử và lỗi, tôi bắt đầu sử dụng tọa độ chuột clientX và clientY trong đối tượng sự kiện jQuery. Các tọa độ này đã cho tôi độ lệch X và Y của chuột so với góc trên cùng bên trái của cổng xem của trình duyệt. Tuy nhiên, khi tôi đang đọc Hướng dẫn tham khảo jQuery 1.4 của Karl Swedberg và Jonathan Chaffer, tôi thấy rằng họ thường nhắc đến tọa độ pageX và pageY. Sau khi kiểm tra tài liệu jQuery đã cập nhật, tôi thấy rằng đây là các tọa độ được chuẩn hóa bởi jQuery; và, tôi thấy rằng họ đã cho tôi độ lệch X và Y của chuột so với toàn bộ tài liệu (không chỉ cổng xem).

Tôi thích event.pageYý tưởng này vì nó sẽ luôn giống nhau, vì nó liên quan đến tài liệu . Tôi có thể so sánh nó với phần tử cha: after của mình bằng offset (), trả về X và Y của nó cũng liên quan đến tài liệu.

Do đó, tôi có thể đưa ra một loạt khu vực "có thể nhấp" trên toàn bộ trang không bao giờ thay đổi.


Đây là bản demo của tôi trên codepen .


hoặc nếu quá lười cho codepen, thì đây là JS:

* Tôi chỉ quan tâm đến các giá trị Y cho ví dụ của tôi.

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

Điều này làm việc cho tôi:

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

6

Câu trả lời ngắn:

Tôi đã làm nó. Tôi đã viết một chức năng cho việc sử dụng năng động cho tất cả những người nhỏ bé ngoài kia ...

Ví dụ làm việc hiển thị trên trang

Ví dụ làm việc đăng nhập vào bàn điều khiển

Câu trả lời dài:

... Vẫn làm điều đó.

Tôi đã mất một lúc để làm điều đó, vì một yếu tố psuedo không thực sự trên trang. Mặc dù một số câu trả lời ở trên hoạt động trong MỘT SỐ kịch bản, nhưng TẤT CẢ chúng không thể động và hoạt động theo kịch bản trong đó một phần tử bất ngờ về kích thước và vị trí (chẳng hạn như các phần tử được định vị tuyệt đối che phủ một phần của phần tử cha). Của tôi thì không.

Sử dụng:

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

});

Làm thế nào nó hoạt động:

Nó lấy các vị trí chiều cao, chiều rộng, trên cùng và bên trái (dựa trên vị trí cách xa mép cửa sổ) của phần tử cha và lấy các vị trí chiều cao, chiều rộng, đỉnh và bên trái (dựa trên cạnh của thùng chứa cha ) và so sánh các giá trị đó để xác định vị trí của phần tử psuedo trên màn hình.

Sau đó, nó so sánh nơi con chuột. Miễn là con chuột nằm trong phạm vi biến mới được tạo thì nó sẽ trả về true.

Ghi chú:

Đó là khôn ngoan để làm cho các yếu tố cha mẹ LIÊN QUAN vị trí. Nếu bạn có một phần tử psuedo được định vị tuyệt đối, chức năng này sẽ chỉ hoạt động nếu nó được định vị dựa trên kích thước của cha mẹ (vì vậy cha mẹ phải tương đối ... có thể dính hoặc cố định cũng sẽ hoạt động .... Tôi không biết).

Mã số:

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

  };      

}

Ủng hộ:

Tôi không biết .... có vẻ như tức là ngu ngốc và thích trả lại tự động như một giá trị được tính toán đôi khi. NÓ CÓ THỂ LÀM VIỆC VÀO TẤT CẢ CÁC DUYỆT NẾU KHI KHAI THÁC ĐƯỢC THIẾT LẬP TRONG CSS. Vì vậy, ... đặt chiều cao và chiều rộng của bạn trên các phần tử psuedo của bạn và chỉ di chuyển chúng với đỉnh và trái. Tôi khuyên bạn nên sử dụng nó trên những thứ mà bạn thấy ổn với nó không hoạt động. Giống như một hình ảnh động hoặc một cái gì đó. Chrome hoạt động ... như bình thường.


eventđược chuyển qua chức năng xử lý sự kiện mỗi khi một sự kiện bị hủy. Giống như nhấp hoặc gõ. Khi chúng tôi sử dụng .click()chức năng, chúng tôi đang chờ sự kiện nhấp chuột. Chúng tôi có thể chỉ định và nói .click(function(e){...})để làm cho sự kiện được enhưng nó cũng được chấp nhận để chỉ sử dụng event.

3
psEUdo, không phải psUEdo!
biziclop

Mã ở trên không hoạt động, vì eventkhông xác định.
Sebastian Zartner

@SebastianZartner - Sự kiện là một từ khóa. Đó là khi người dùng làm một cái gì đó. Tôi thực sự giải thích hai ý kiến ​​trên bình luận của bạn. Khi người dùng tương tác với trang, một sự kiện sẽ bị loại bỏ (trong hầu hết các trường hợp). Sự kiện là một từ khóa đến từ người nghe sự kiện ".click ()". Nếu nhà phát triển muốn sử dụng một tên khác cho sự kiện, họ có thể thiết lập nó trong trình nghe sự kiện như ".click (e)", một cách phổ biến hơn để xem nó. TUY NHIÊN .... mặc dù tôi có một liên kết hoạt động ở trên, tôi cũng sẽ bao gồm một liên kết rõ ràng hơn và không đăng nhập vào bảng điều khiển mà thay vào đó là trang cho người cần.

Tôi nên đã đề cập rằng nó không hoạt động trong Firefox, vì không eventxác định được. Mặc dù vậy, nó hoạt động trong Chrome và Edge.
Sebastian Zartner

2

Thêm điều kiện trong sự kiện Click để hạn chế vùng có thể nhấp.

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

BẢN GIỚI THIỆU


1

Đây là câu trả lời được chỉnh sửa bởi Fasoeu với CSS3 và JS ES6 mới nhất

Đã chỉnh sửa bản demo mà không sử dụng JQuery.

Ví dụ ngắn nhất về mã:

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

Giải trình:

pointer-eventsphát hiện kiểm soát các sự kiện, tháo nhận sự kiện từ mục tiêu, nhưng phải ghi nhận từ giả các yếu tố làm cho có thể bấm vào ::before::aftervà bạn sẽ luôn luôn biết những gì bạn đang bấm vào phần tử giả, tuy nhiên nếu bạn vẫn cần phải nhấp chuột, bạn đặt tất cả nội dung trong phần tử lồng nhau ( spanví dụ), nhưng vì chúng tôi không muốn áp dụng bất kỳ kiểu bổ sung nào, display: contents;trở thành giải pháp rất tiện dụng và được hầu hết các trình duyệt hỗ trợ . pointer-events: none;như đã đề cập trong bài viết gốc cũng được hỗ trợ rộng rãi .

Phần JavaScript cũng được sử dụng rộng rãi được hỗ trợ Array.fromfor...oftuy nhiên chúng không cần thiết phải sử dụng trong mã.


0

Không có câu trả lời nào trong số này là đáng tin cậy, và tôi sẽ không đáng tin cậy hơn nhiều.

Hãy tránh sang một bên, nếu bạn gặp phải tình huống may mắn khi phần tử bạn đang cố gắng nhấp không có phần đệm (sao cho tất cả không gian "bên trong" của phần tử được bao phủ hoàn toàn bởi các phần tử phụ), thì bạn có thể kiểm tra mục tiêu của sự kiện nhấp vào chính container. Nếu nó khớp, điều đó có nghĩa là bạn đã nhấp vào phần tử: trước hoặc: sau.

Rõ ràng điều này sẽ không khả thi với cả hai loại (trước và sau) tuy nhiên tôi đã triển khai nó dưới dạng hack / speed fix và nó hoạt động rất tốt, không có một loạt các kiểm tra vị trí, có thể không chính xác tùy thuộc vào khoảng một triệu yếu tố khác nhau .


-2

Không, nhưng bạn có thể làm như thế này

Trong tệp html thêm phần này

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

Trong css bạn có thể làm như thế này

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

} Hy vọng nó sẽ giúp bạn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.