Hanya deteksi acara klik pada elemen semu

213

Kode saya adalah:

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

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

Silakan lihat biola ini: http://jsfiddle.net/ZWw3Z/5/

Saya ingin memicu acara klik hanya pada elemen pseudo (bit merah). Artinya, saya tidak ingin acara klik dipicu pada bit biru.

Randomblue
sumber
1
Bagaimana dengan memeriksa pos yang diklik? stackoverflow.com/questions/3234977/…
Silakan baca solusi saya yang sebelumnya diposting di sini .
Amr
Mungkin solusi yang baik DI SINI .
Reza Mamun

Jawaban:

218

Ini tidak mungkin; pseudo-elements sama sekali bukan bagian dari DOM sehingga Anda tidak dapat mengikat acara apa pun secara langsung dengannya, Anda hanya dapat mengikat elemen induknya.

Jika Anda harus memiliki penangan klik pada wilayah merah saja, Anda harus membuat elemen turunan, seperti a span, meletakkannya tepat setelah <p>tag pembuka , menerapkan gaya p spanbukan p:before, dan mengikatnya.

BoltClock
sumber
108
Tampaknya di peramban modern ini mungkin terjadi dengan pointer-eventsnilai yang berbeda untuk elemen itu sendiri dan elemen pseudo-nya: jsfiddle.net/ZWw3Z/70
Ilya Streltsyn
5
@Ilya Streltsyn luar biasa - bukan jawaban yang 'benar' (tidak akan bekerja jika Anda juga perlu mengklik elemen) tetapi bekerja dengan gemilang untuk 'tombol tutup' pada
div
pointer-eventstampaknya tidak melakukan trik untuk IE9, menurut jsfiddel yang diposting Ilya.
user393274
@ user393274: IE9 tidak mendukung peristiwa-pointer di luar SVG.
BoltClock
1
@ mereka tidak, pada halaman itu seluruh baris dapat diklik, baik di kiri dan di kanan dari tautan. Hanya tautan itu sendiri yang memiliki penangan klik yang berbeda, jadi mengkliknya tidak memicu lipatan / lipatan yang terbuka.
Ilya Streltsyn
131

Sebenarnya itu mungkin. Anda dapat memeriksa apakah posisi yang diklik berada di luar elemen, karena ini hanya akan terjadi jika ::beforeatau ::afterdiklik.

Contoh ini hanya memeriksa elemen di sebelah kanan tetapi itu akan berfungsi dalam kasus Anda.

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

Linus Unnebäck
sumber
1
Ini tidak berfungsi untuk saya, teks akan disorot ketika saya mengklik salah satu. Menggunakan Firefox, jika itu penting (tidak boleh).
Flater
2
untuk firefox: jsfiddle.net/wC2p7/16 . Jika bekerja dengan elemen bersarang, Anda mungkin perlu menghitung offset yang sesuai (mis. JQuery: $ (e.target) .offset (). Left)
bebbi
1
Pria yang luar biasa terima kasih, ini berhasil. Tetapi di Firefox dan browser lain yang sesuai standar, untuk menguji apakah mouse :afterAnda harus memeriksa if (e.clientX > span.offsetLeft + span.offsetHeight)karena browser ini tidak memiliki e.offsetXproperti. Fiddle: jsfiddle.net/Noitidart/wC2p7/18
Noitidart
5
Lebih keren lagi jika jQuery memutuskan untuk mendukung $('a:after').on('click', fn)tapi saya tidak benar-benar melihat itu terjadi: p
Linus Unnebäck
25
Ini sebenarnya tidak akan berfungsi jika ::beforeatau ::afterdiposisikan di dalam elemen.
laconbass
74

Pada peramban modern, Anda dapat mencoba dengan properti pointer-event css (tetapi itu mengarah pada ketidakmungkinan untuk mendeteksi peristiwa mouse pada simpul induk):

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

Ketika target acara adalah elemen "p" Anda, Anda tahu itu adalah "p: sebelum" Anda.

Jika Anda masih perlu mendeteksi acara mouse pada p utama, Anda dapat mempertimbangkan kemungkinan untuk mengubah struktur HTML Anda. Anda dapat menambahkan tag rentang dan gaya berikut:

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

Target acara sekarang adalah elemen "span" dan "p: before".

Contoh tanpa jquery: http://jsfiddle.net/2nsptvcu/

Contoh dengan jquery: http://jsfiddle.net/0vygmnnb/

Berikut adalah daftar browser yang mendukung pointer-events: http://caniuse.com/#feat=pointer-events

Fasoeu
sumber
Saya tidak tahu mengapa simpul orangtua. Apakah Anda mengatakan bahwa jika saya mengeklik acara pada sesuatu seperti .box: sebelumnya, maka .box tidak dapat mendeteksi klik apa pun?
Yang Mulia,
Itu sebagian benar: jika CSS Anda berisi sesuatu seperti .box {pointer-events: none;} .box: before {pointer-events: auto;} maka satu-satunya elemen yang masih mendukung acara adalah p: sebelumnya. Ingat pula bahwa js akan memberi Anda kembali elemen .box utama sejak .box: sebelumnya tidak benar-benar tinggal di The DOM.
Fasoeu
9

Jawaban saya akan bekerja untuk siapa saja yang ingin mengklik area halaman yang pasti. Ini bekerja untuk saya pada posisi saya yang benar-benar: setelah

Berkat artikel ini , saya menyadari (dengan jQuery) saya dapat menggunakan e.pageYdan e.pageXbukannya mengkhawatirkan tentang e.offsetY/Xdan e.clientY/Xmengeluarkan antar browser.

Melalui coba-coba, saya mulai menggunakan koordinat mouse clientX dan clientY di objek acara jQuery. Koordinat ini memberi saya offset X dan Y dari tetikus relatif ke sudut kiri atas port tampilan browser. Ketika saya membaca Panduan Referensi jQuery 1.4 oleh Karl Swedberg dan Jonathan Chaffer, saya melihat bahwa mereka sering merujuk ke koordinat pageX dan pageY. Setelah memeriksa dokumentasi jQuery yang diperbarui, saya melihat bahwa ini adalah koordinat yang distandarisasi oleh jQuery; dan, saya melihat bahwa mereka memberi saya offset X dan Y dari mouse relatif ke seluruh dokumen (bukan hanya port view).

Saya menyukai event.pageYide ini karena akan selalu sama, karena itu relatif terhadap dokumen . Saya dapat membandingkannya dengan elemen induk after: saya menggunakan offset (), yang mengembalikan X dan Y juga relatif terhadap dokumen.

Oleh karena itu, saya dapat membuat berbagai wilayah "dapat diklik" di seluruh halaman yang tidak pernah berubah.


Ini demo saya tentang codepen .


atau jika terlalu malas untuk codepen, inilah JS:

* Saya hanya peduli tentang nilai-nilai Y untuk contoh saya.

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

Ini bekerja untuk saya:

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

Jawaban singkat:

Saya melakukannya. Saya menulis fungsi untuk penggunaan dinamis untuk semua orang kecil di luar sana ...

Contoh kerja yang ditampilkan pada halaman

Bekerja contoh masuk ke konsol

Jawaban panjang:

... Masih melakukannya.

Butuh beberapa saat untuk melakukannya, karena elemen psuedo tidak benar-benar ada di halaman. Sementara beberapa jawaban di atas berfungsi dalam skenario BEBERAPA, mereka SEMUA gagal menjadi dinamis dan bekerja dalam skenario di mana elemen keduanya tidak terduga dalam ukuran dan posisi (seperti elemen diposisikan mutlak overlay bagian dari elemen induk). Milik saya tidak.

Pemakaian:

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

});

Bagaimana itu bekerja:

Ia meraih posisi tinggi, lebar, atas, dan kiri (berdasarkan posisi yang jauh dari tepi jendela) elemen induk dan meraih posisi tinggi, lebar, atas, dan kiri (berdasarkan tepi wadah induk ) dan membandingkan nilai-nilai tersebut untuk menentukan di mana elemen psuedo berada di layar.

Kemudian membandingkan di mana mouse berada. Selama mouse berada dalam rentang variabel yang baru dibuat maka ia mengembalikan true.

catatan:

Adalah bijaksana untuk membuat elemen induk RELATIF diposisikan. Jika Anda memiliki elemen psuedo yang benar-benar diposisikan, fungsi ini hanya akan berfungsi jika diposisikan berdasarkan dimensi induknya (sehingga induknya harus relatif ... mungkin lengket atau tetap akan berfungsi juga .... Saya tidak tahu).

Kode:

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

  };      

}

Dukung:

Saya tidak tahu .... sepertinya itu bodoh dan suka mengembalikan otomatis sebagai nilai yang dihitung terkadang. TAMPAKNYA BEKERJA DENGAN BAIK DALAM SEMUA BROWSER JIKA DIMENSI DIRANCANG DALAM CSS. Jadi ... atur tinggi dan lebar Anda pada elemen psuedo Anda dan hanya gerakkan dengan atas dan kiri. Saya sarankan menggunakannya pada hal-hal yang Anda tidak masalah dengan itu tidak berfungsi. Seperti animasi atau semacamnya. Chrome berfungsi ... seperti biasa.


sumber
eventdilewatkan melalui fungsi event handler setiap kali suatu peristiwa dimatikan. Suka mengklik atau mengetik. Saat kami menggunakan .click()fungsinya, kami menunggu acara klik. Kita dapat menentukan dan mengatakan .click(function(e){...})untuk membuat acara menjadi etetapi itu juga dapat diterima untuk hanya menggunakan event.
3
psEUdo, bukan psUEdo!
biziclop
Kode di atas tidak berfungsi, karena eventtidak terdefinisi.
Sebastian Zartner
@SebastianZartner - Acara adalah kata kunci. Itu adalah ketika pengguna melakukan sesuatu. Saya benar-benar menjelaskan dua komentar di atas komentar Anda. Ketika pengguna berinteraksi dengan halaman, suatu peristiwa dimatikan (dalam kebanyakan kasus). Acara adalah kata kunci yang berasal dari pendengar acara ".click ()". Jika pengembang ingin menggunakan nama yang berbeda untuk acara, mereka dapat mengaturnya di pendengar acara seperti ".click (e)" yang merupakan cara yang lebih umum untuk melihatnya. NAMUN .... meskipun saya memiliki tautan yang berfungsi di atas, saya juga akan memasukkan satu yang lebih jelas dan tidak masuk ke konsol tetapi sebaliknya ke halaman untuk yang membutuhkan.
Saya seharusnya menyebutkan bahwa itu tidak berfungsi di Firefox, karena ada eventyang tidak ditentukan. Ini bekerja di Chrome dan Edge.
Sebastian Zartner
2

Tambahkan kondisi di acara Klik untuk membatasi area yang dapat diklik.

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

Abdennour TOUMI
sumber
1

Ini adalah jawaban yang diedit oleh Fasoeu dengan CSS3 dan JS ES6 terbaru

Demo yang diedit tanpa menggunakan JQuery.

Contoh kode terpendek:

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

Penjelasan:

pointer-eventsmengontrol deteksi peristiwa, menghapus acara penerimaan dari target, tetapi tetap menerima dari elemen semu memungkinkan untuk mengklik ::beforedan ::afterdan Anda akan selalu tahu apa yang Anda klik pada elemen semu, namun jika Anda masih perlu mengklik, Anda meletakkan semua konten dalam elemen bersarang ( spanmisalnya), tetapi karena kami tidak ingin menerapkan gaya tambahan, display: contents;menjadi solusi yang sangat praktis dan didukung oleh sebagian besar browser . pointer-events: none;seperti yang sudah disebutkan di posting asli juga banyak didukung .

Bagian JavaScript juga digunakan secara luas didukung Array.fromdan for...of, bagaimanapun, mereka tidak perlu digunakan dalam kode.

XCanG
sumber
0

Tidak satu pun dari jawaban ini yang dapat diandalkan, dan jawaban saya tidak akan lebih dapat diandalkan.

Selain peringatan, jika Anda masuk ke skenario beruntung di mana elemen yang Anda coba klik tidak memiliki padding (sehingga semua ruang "bagian dalam" elemen tersebut sepenuhnya ditutupi oleh sub-elemen), maka Anda dapat memeriksa target acara klik terhadap wadah itu sendiri. Jika cocok, itu berarti Anda telah mengklik elemen: sebelum atau: setelah.

Jelas ini tidak akan layak dengan kedua jenis (sebelum dan sesudah) namun saya telah menerapkannya sebagai peretasan / perbaikan kecepatan dan berfungsi dengan baik, tanpa banyak pengecekan posisi, yang mungkin tidak akurat tergantung pada sekitar sejuta faktor yang berbeda .

dudewad
sumber
-2

Tidak, tetapi Anda dapat melakukannya seperti ini

Dalam file html, tambahkan bagian ini

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

Dalam css Anda bisa melakukan ini

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

} Semoga ini akan membantu Anda

Gopal Bogati
sumber