疑似要素のクリックイベントのみを検出


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
クリックされたposをチェックするのはどうですか? stackoverflow.com/questions/3234977/...

私の以前に投稿したソリューションをここで読んでください。
Amr 2017年

おそらく良い回避策はここにあります。
Reza Mamun

回答:


218

これは不可能です; 疑似要素はDOMの一部ではないため、イベントを直接それらにバインドすることはできません。親要素にのみバインドできます。

赤い領域にのみクリックハンドラーが必要な場合は、のような子要素を作成しspan、開始<p>タグの直後に配置して、のp span代わりにスタイルを適用しp:before、それにバインドする必要があります。


108
最近のブラウザでは、これはpointer-events要素自体とその疑似要素に異なる値を使用することである程度
Ilya Streltsyn 14

5
@Ilya Streltsynすばらしい-「正しい」答えではない(要素をクリックする必要がある場合は機能しない)が、
divの

pointer-eventsIlyaが投稿したjsfiddelによると、IE9のトリックを実行していないようです。
user393274

@ user393274:IE9は、SVG外のポインターイベントをサポートしていません。
BoltClock

1
@theyuvいいえ、そのページでは、リンクから左側と右側の両方で行全体をクリックできます。リンク自体だけが異なるクリックハンドラーを持っているので、リンクをクリックしても、サブツリーの折りたたみ/展開はトリガーされません。
Ilya Streltsyn 2017

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を使用する(すべきではない)。
2014

2
Firefoxの場合: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 2014

5
jQueryがサポートすることを決定した場合、さらにクールになりますが、$('a:after').on('click', fn)実際にはそのことがわかりません。:p
LinusUnnebäck14年

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構造を変更する可能性を検討できます。spanタグと次のスタイルを追加できます。

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

イベントターゲットは「スパン」要素と「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です。とにかく、.box:beforeは実際にはDOMに存在しないため、jsがメインの.box要素を返すことを覚えておいてください。
Fasoeu 2017

9

私の答えは、ページの最も明確な領域をクリックしたい人のために機能します。これは私の絶対的な位置に私のために働いた:後

このおかげ記事は、私が使用することができます(jQueryを使って)を実現e.pageYし、e.pageX代わりの心配のe.offsetY/Xe.clientY/Xブラウザ間の問題。

私は試行錯誤を繰り返し、jQueryイベントオブジェクトでclientXおよびclientYマウス座標を使用し始めました。これらの座標により、ブラウザのビューポートの左上隅に対するマウスのXおよびYオフセットがわかりました。しかし、Karl SwedbergとJonathan ChafferによるjQuery 1.4リファレンスガイドを読んでいると、彼らはしばしばpageXとpageY座標を参照することがわかりました。更新されたjQueryドキュメントを確認したところ、これらがjQueryによって標準化された座標であることがわかりました。そして、ドキュメント全体(ビューポートだけでなく)に対するマウスのXオフセットとYオフセットが与えられているのがわかりました。

このevent.pageYアイデアは、ドキュメントと比較して常に同じであるため、気に入りました。これを、ドキュメントに対するXとYも返すoffset()を使用して、私の:afterの親要素と比較できます。

したがって、ページ全体で変化しない「クリック可能な」領域の範囲を考え出すことができます。


これが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

短い答え:

やったよ。私はそこにいるすべての小さな人々のための動的使用のための関数を書きました...

ページに表示される実例

コンソールへのロギングの実例

長い答え:

...それでもやった。

疑似要素は実際にはページ上にないため、それを行うには少し時間がかかりました。上記の回答の一部は一部のシナリオで機能しますが、すべてが動的でなく、要素のサイズと位置が両方とも予期しないシナリオ(親要素の一部を覆う絶対配置要素など)で機能しません。私はしません。

使用法:

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

});

使い方:

親要素の高さ、幅、上、左の位置(ウィンドウの端から離れた位置に基づく)を取得し、高さ、幅、上、左の位置(親コンテナの端に基づく)を取得します。 )、それらの値を比較して、疑似要素が画面上のどこにあるかを判断します。

次に、マウスの位置を比較します。マウスが新しく作成された変数の範囲内にある限り、trueを返します。

注意:

親要素をRELATIVEに配置することをお勧めします。絶対配置された疑似要素がある場合、この関数は、親の寸法に基づいて配置されている場合にのみ機能します(したがって、親は相対的である必要があります...スティッキーまたは固定も機能する可能性があります...わかりません)。

コード:

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

  };      

}

サポート:

わからない....それはつまり、馬鹿げているように見え、計算された値としてautoを返すことが好きな場合があります。寸法がCSSで設定されている場合、すべてのブラウザでうまく機能するようです。だから...あなたの高さと幅を疑似要素に設定し、上と左だけでそれらを動かしてください。動作しないことで大丈夫なものに使用することをお勧めします。アニメーションのようなものです。Chromeは正常に動作します。


eventイベントが発生するたびに、イベントハンドラー関数を介して渡されます。クリックや入力のように。.click()関数を使用するときは、クリックイベントを待機しています。.click(function(e){...})イベントを指定して指定することもできますがe、そのまま使用することもできますevent

3
psUEdoではなく、psEUdo!
biziclop

上記のコードeventは、未定義であるため機能しません。
Sebastian Zartner、

@SebastianZartner-イベントはキーワードです。それはユーザーが何かをするときです。この2つのコメントをコメントの上に文字通り説明しました。ユーザーがページを操作すると、イベントが発生します(ほとんどの場合)。イベントは、イベントリスナー「.click()」から送信されるキーワードです。開発者がイベントに別の名前を使用する場合は、「。click(e)」のようにイベントリスナーで設定することができます。これは、より一般的な方法です。ただし、上記で機能しているリンクがあっても、コンソールにログを記録せず、代わりに必要なページにログを記録する、より明確なリンクも含めます。

まだevent定義されていないため、Firefoxでは機能しないことを述べておきます。ただし、ChromeとEdgeで動作します。
Sebastian Zartner

2

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

デモ


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;元の投稿ですでに述べたように、広くサポートされています。

JavaScriptパーツも広くサポートされてArray.fromおりfor...of、コードで使用する必要はありません。


0

これらの答えはどれも信頼できず、私のものははるかに信頼できません。

注意点は別として、クリックしようとしている要素にパディングがない(要素の「内部」スペースのすべてがサブ要素で完全に覆われているような)幸運なシナリオに陥った場合、コンテナ自体に対してクリックイベントのターゲットをチェックできます。一致する場合は、: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.