Yalnızca sözde öğede tıklama olayını algıla


213

Kodum:

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

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

Lütfen bu kemanı görün: http://jsfiddle.net/ZWw3Z/5/

Ben sadece sözde eleman (kırmızı bit) bir tıklama olayı tetiklemek istiyorum. Yani, tıklama olayının mavi bitte tetiklenmesini istemiyorum.


1
Tıklanan pos kontrol etmeye ne dersiniz? stackoverflow.com/questions/3234977/…

Lütfen daha önce gönderdiğim çözümü buradan okuyun .
Amr

Muhtemelen BURADA iyi bir çözüm .
Reza Mamun

Yanıtlar:


218

Bu mümkün değil; sözde öğeler DOM'un bir parçası değildir, bu nedenle herhangi bir etkinliği doğrudan bunlara bağlayamazsınız, yalnızca üst öğelerine bağlanabilirsiniz.

Yalnızca kırmızı bölgede bir tıklama işleyiciniz olması gerekiyorsa, a gibi bir alt öğe oluşturmanız, spanaçılış <p>etiketinin hemen sonrasına yerleştirmeniz , p spanyerine stiller uygulamanız p:beforeve buna bağlamanız gerekir.


108
Modern tarayıcılarda bu, pointer-eventsöğenin kendisi ve sözde öğesi için farklı değerlerle mümkün görünüyor : jsfiddle.net/ZWw3Z/70
Ilya

5
@Ilya Streltsyn şaşırtıcı - 'doğru' cevap değil (öğeyi de tıklamanız gerekiyorsa işe yaramaz), ancak
div'de

pointer-events Ilya tarafından yayınlanan jsfiddel göre IE9 için hile yapmak görünmüyor.
user393274

@ user393274: IE9, SVG dışındaki işaretçi olaylarını desteklemiyor.
BoltClock

1
@theyuv no, bu sayfada tüm satır, hem soldan hem de sağdan bağlantıdan tıklanabilir. Yalnızca bağlantının kendisinin farklı bir tıklama işleyicisi vardır, bu nedenle tıklandığında alt / katlanan alt ağaç tetiklenmez.
Ilya Streltsyn

131

Aslında mümkün. Tıklanan konumun öğenin dışında olup olmadığını kontrol edebilirsiniz, çünkü bu yalnızca tıklandığında ::beforeveya ::aftertıklandığında gerçekleşir.

Bu örnek yalnızca sağdaki öğeyi kontrol eder, ancak bu sizin durumunuzda işe yarayacaktır.

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
Benim için işe yaramıyor, ben de tıkladığımda metin vurgulanıyor. Önemli ise Firefox'u kullanmak (olmamalı).
Flater

2
firefox için: jsfiddle.net/wC2p7/16 . Yuvalanmış öğelerle çalışıyorsanız, yuvalanmış ötelemeleri uygun şekilde hesaplamanız gerekebilir (örn. JQuery: $ (e.target) .offset (). Sol)
bebbi

1
Harika adam teşekkürler, işe yarıyor. Ancak Firefox ve diğer standartlara uygun tarayıcılarda, farenin üzerinde olup olmadığını test :afteretmek if (e.clientX > span.offsetLeft + span.offsetHeight)için bu tarayıcıların e.offsetXözelliği olmadığından emin olmanız gerekir . Keman: jsfiddle.net/Noitidart/wC2p7/18
Noitidart

5
Hatta jQuery desteklemeye karar verirse daha serin olurdu $('a:after').on('click', fn)ama bunu gerçekten görmüyorum: p
Linus Unnebäck

25
Elemanın içine yerleştirilirse ::beforeveya ::afteryerleştirilirse bu gerçekten işe yaramaz .
laconbass

74

On modern tarayıcılarda Eğer işaretçi-olaylar css özelliğiyle deneyebilirsiniz (ancak ana düğümünde fare olaylarını tespit etmek imkansızlığı yol açar):

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

Etkinlik hedefi "p" öğeniz olduğunda, bunun "p: before" öğeniz olduğunu bilirsiniz.

Ana p'deki fare olaylarını hala tespit etmeniz gerekiyorsa, HTML yapınızı değiştirme olasılığını düşünebilirsiniz. Bir span etiketi ve aşağıdaki stili ekleyebilirsiniz :

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

Etkinlik hedefleri artık hem "span" hem de "p: before" öğeleridir.

Jquery'siz örnek: http://jsfiddle.net/2nsptvcu/

Jquery ile örnek: http://jsfiddle.net/0vygmnnb/

İşaretçi etkinliklerini destekleyen tarayıcıların listesi: http://caniuse.com/#feat=pointer-events


Ana düğümün neden olduğunu bilmiyorum. Eğer .box: gibi bir şeyde click olayı olursa, o zaman .box'ın herhangi bir tıklamayı algılayamadığını mı söylüyorsunuz?
en saygıdeğer efendim

Bu kısmen doğrudur: CSS'niz .box {pointer-events: none;} .box: before {pointer-events: auto;} gibi bir şey içeriyorsa, hala etkinlikleri destekleyen tek öğe p: before olur. Yine de, js'in ana .box öğesini size geri vereceğini unutmayın. .Box: daha önce DOM'da gerçekten yaşamıyor.
Fasoeu

9

Cevabım, sayfanın belirli bir alanını tıklamak isteyen herkes için işe yarayacaktır. Bu benim için çalıştı kesinlikle konumlandırılmış : sonra

Bu sayede makalede , ben kullanabilirsiniz (jQuery ile) gerçekleştirilen e.pageYve e.pageXüzülmek yerine e.offsetY/Xve e.clientY/Xkonu tarayıcılar arasında.

Deneme yanılma yoluyla, jQuery olay nesnesindeki clientX ve clientY fare koordinatlarını kullanmaya başladım. Bu koordinatlar bana tarayıcının görünüm bağlantı noktasının sol üst köşesine göre farenin X ve Y ofsetini verdi. Ancak Karl Swedberg ve Jonathan Chaffer'ın jQuery 1.4 Referans Kılavuzunu okurken, genellikle pageX ve pageY koordinatlarına atıfta bulunduklarını gördüm. Güncellenmiş jQuery belgelerini kontrol ettikten sonra, bunların jQuery tarafından standartlaştırılmış koordinatlar olduğunu gördüm; ve bana tüm belgeye göre farenin X ve Y ofsetini verdiklerini gördüm (sadece görüntüleme portuna değil).

Bu event.pageYfikri sevdim çünkü belgeye göre her zaman aynı olurdu . Bunu x: Y değerini de belgeye göre döndüren offset () kullanarak my: after öğesinin üst öğesiyle karşılaştırabilirim.

Bu nedenle, tüm sayfada hiçbir zaman değişmeyen bir dizi "tıklanabilir" bölge bulabilirim.


İşte benim var codepen üzerinde demo .


veya codepen için çok tembel ise, JS:

* Örneğim için sadece Y değerlerine önem verdim.

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

Bu benim için çalışıyor:

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

6

Kısa cevap:

Yaptım. Dışarıdaki tüm küçük insanlar için dinamik kullanım için bir fonksiyon yazdım ...

Sayfada görüntülenen çalışma örneği

Konsolda çalışma örneği günlüğü

Uzun cevap:

... Hala yaptı.

Bunu yapmak biraz zaman aldı, çünkü bir psuedo öğesi gerçekten sayfada değil. Yukarıdaki yanıtlardan bazıları BAZI senaryolarda çalışırken, TÜMÜ hem dinamik hem de bir öğenin hem boyut hem de konumda beklenmedik olduğu bir senaryoda (ana öğenin bir bölümünü kaplayan mutlak konumlandırılmış öğeler gibi) çalışmaz. Benimki değil.

Kullanımı:

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

});

Nasıl çalışır:

Üst öğenin yükseklik, genişlik, üst ve sol konumlarını (pencerenin kenarından uzaktaki konuma göre) yakalar ve (ana kabın kenarına bağlı olarak) yükseklik, genişlik, üst ve sol konumları yakalar ) ve psuedo öğesinin ekranda nerede olduğunu belirlemek için bu değerleri karşılaştırır.

Daha sonra farenin yerini karşılaştırır. Fare yeni oluşturulan değişken aralığında olduğu sürece true değerini döndürür.

Not:

Ana öğenin RELATIVE olmasını sağlamak akıllıca olacaktır. Mutlak konumlandırılmış bir psuedo öğeniz varsa, bu işlev yalnızca ebeveynin boyutlarına göre konumlandırılırsa çalışır (bu nedenle ebeveyn göreli olmalıdır ... belki yapışkan veya sabit de çalışır ... Bilmiyorum).

Kod:

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

  };      

}

Destek:

Bilmiyorum .... yani aptal gibi görünüyor ve bazen hesaplanan bir değer olarak otomatik dönmek seviyor. ÖLÇÜLER CSS'DE AYARLANMIŞSA, TÜM TARAYICILARDA ÇALIŞMAK İSTİYOR. Yani ... boyunuzu ve genişliğinizi psuedo elemanlarınıza ayarlayın ve sadece üst ve sola hareket ettirin. Üzerinde çalışmamanız iyi olan şeylerde kullanmanızı öneririm. Bir animasyon falan gibi. Chrome her zamanki gibi çalışıyor.


eventbir olay her tetiklendiğinde bir olay işleyici işlevinden geçirilir. Tıklamak veya yazmak gibi. .click()İşlevi kullandığımızda , click etkinliğini bekliyoruz. .click(function(e){...})Olayın gerçekleşmesini belirleyip söyleyebiliriz , eancak sadece kullanmak da kabul edilebilir event.

3
psEUdo, psUEdo değil!
biziclop

eventUndefined olduğundan yukarıdaki kod çalışmıyor .
Sebastian Zartner

@SebastianZartner - Etkinlik bir anahtar kelime. Kullanıcının bir şey yaptığı zamandır. Bu iki yorumu tam olarak yorumunuzun üstünde açıkladım. Kullanıcı sayfa ile etkileşime girdiğinde bir etkinlik tetiklenir (çoğu durumda). Etkinlik, ".click ()" etkinlik dinleyicisinden gelen bir anahtar kelimedir. Bir geliştirici olay için farklı bir ad kullanmak istiyorsa, olay dinleyicisinde ".click (e)" gibi olay dinleyicisini daha sık görmenin bir yolu olarak ayarlayabilir. ANCAK .... Ben yukarıda çalışan bir bağlantı olsa bile, ben de daha bariz ve konsola değil, muhtaç sayfa yerine günlük bir tane içerir.

Firefox'ta işe yaramadığından bahsetmeliydim, çünkü eventtanımsız. Yine de Chrome ve Edge'de çalışıyor.
Sebastian Zartner

2

Tıklanabilir alanı kısıtlamak için Click olayına koşul ekle.

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


1

Bu cevap en son CSS3 ve JS ES6 ile Fasoeu tarafından düzenlenmiştir

Demoyu JQuery kullanmadan düzenledi.

En kısa kod örneği:

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

Açıklama:

pointer-eventsOlayların kontrol tespiti, hedefin olay almayı kaldırarak, ancak sözde elementlerden almaya devam tıklayın mümkün kılan ::beforeve ::afterve her zaman yine tıklamanız gerekir ancak eğer sözde elemanından tıklayarak ne bilecek, tüm içerik koymak iç içe öğede ( spanörneğin), ancak herhangi bir ek stil uygulamak istemediğimiz için display: contents;çok kullanışlı bir çözüm haline gelir ve çoğu tarayıcı tarafından desteklenir . pointer-events: none;orijinal yazı zaten belirtildiği gibi de yaygın olarak desteklenen .

JavaScript parçası da yaygın olarak desteklenen kullanılan Array.fromve for...ofonlar kodunda kullanmak gerekli değildir ancak,.


0

Bu cevapların hiçbiri güvenilir değildir ve benimkiler çok daha güvenilir olmayacaktır.

Uyarılar bir yana, tıklamaya çalıştığınız öğenin dolgusu olmadığı şanslı senaryoya girerseniz (öğenin "iç" alanının tamamı alt öğelerle kaplanacak şekilde), tıklama etkinliğinin hedefini kapsayıcıya göre kontrol edebilir. Eşleşirse, bu: a: before veya: after öğesini tıkladığınız anlamına gelir.

Açıkçası bu her iki tiple de (önce ve sonra) mümkün olmaz, ancak bunu bir hack / hız düzeltmesi olarak uyguladım ve yaklaşık bir milyon farklı faktöre bağlı olarak yanlış olabilecek bir grup konum kontrolü olmadan çok iyi çalışıyor. .


-2

Hayır, ama bunu yapabilirsin

Html dosyasına bu bölümü ekleyin

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

Css içinde bunu yapabilirsiniz

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

} Umarım sana yardımcı olur

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.