web-dev-qa-db-ja.com

HTMLラベルをクリックすると、jqueryクリックイベントが2回トリガーされる

HTMLチェックボックスとそのラベルを含むdivコンテナーがあります。 jqueryを使用して、誰かがこのコンテナのラベルをクリックしたときにクリックイベントをトリガーしたかった。

ラベルをクリックすると、jqueryクリックイベントが2回トリガーされることがわかります。

テスト目的で、ラベルの代わりにチェックボックスでクリックイベントをトリガーしました。ここでは、チェックボックスクリックイベントは必要なときに一度だけトリガーされます。

ここにフィドルがあります。 http://jsfiddle.net/AnNvJ/2/

<tr>
    <td>
        <div id="test">
            <label>
                <input type="checkbox" id="1" />demo1</label>
            <label>
                <input type="checkbox" id="2" />demo2</label>
            <label>
                <input type="checkbox" id="3" />demo3</label>
        </div>
    </td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
</tr>

JQUERY

$(document).ready(function () {

    $('#test label').live('click', function (event) {
        alert('clicked');
    });


    $('#test checkbox').live('click', function (event) {
        alert('clicked');
    });

});
29
sravis

checkboxという名前のタグがないため、$('#test checkbox')の1つは呼び出されません。

チェックボックスまたはラベルをクリックしたかどうかに応じて、$('#test label')のコールバックが1回または2回呼び出されます バブリングの原因 入力要素はラベルの一部であり、1つunionであり、したがってラベルがクリックされた場合(バブルではない場合はイベントも受信できるため、 'event.stopPropagation())しません。

この方法でコードを変更する場合、これを確認できます。

 $('#test label').live('click', function (event) {
        event.stopPropagation(); //<-- has no effect to the described behavior
        console.log(event.target.tagName);
 });

ラベルをクリックします。

LABEL
入力

入力をクリックします。

入力

[〜#〜] edit [〜#〜]チェックボックスではなく、labelのクリックのみを処理する場合-HTML構造を変更できない場合- input要素のイベントを単にignoreできます。

どちらかの方法:

$('#test label').live('click', function (event) {
    if( event.target.tagName === "LABEL" ) {
         alert('clicked');
    }
});

または、jQueryを使用してテストします。

$('#test label').live('click', function (event) {
    if( $(event.target).is("label") ) {
         alert('clicked');
    }
});
40
t.niese

ラベル内に入力を配置したため、チェックボックスをクリックすると、すべての親(バブリングと呼ばれます)もクリックするためです。 編集、@ t.nieseの功績:ラベルをクリックしたときに問題が発生し、バブルが発生するだけなので、実際にはバブルは発生しません。

ダブルクリックイベントを防ぐだけでなく、使用できるチェックボックスをチェックするには:

$(document).ready(function () {

    $('#test label').on('click', function (event) {
        event.preventDefault();
        var $check = $(':checkbox', this);
        $check.prop('checked', !$check.prop('checked'));
        alert('clicked label');
    });


    $('#test :checkbox').on('click', function (event) {
        event.stopPropagation();
        alert('clicked checkbox');
    });
});

[〜#〜] fiddle [〜#〜]

また、 $.on の使用を好み、 :checkbox selector または[type="checkbox"]の使用に注意してください。互換性がある( 属性セレクター

event.preventDefault()は、ブラウザによって処理されるネイティブタグのすべてのアクションを停止しますevent.stopPropagation()は、バブリングおよびすべての親ハンドラーにイベントが通知されないようにします

9
TecHunter

OPは、ラベルのクリックイベントハンドラーが1回のクリックで2回実行されるのを防ぐ1つのソリューションを見つけました。選択した回答にも良い解決策がありますが、イベントバブリングとは関係がないと誤って述べています。

2回クリックする理由は、イベントのバブリングに関係しています。

入力に関連付けられているラベルをクリックすると、2つのクリックイベントがトリガーされます。ラベルの最初のクリックイベントがトリガーされます。そのクリックイベントのデフォルトの処理により、関連する入力に対して2番目のクリックイベントがトリガーされます。入力がラベルの子孫である場合、2番目のクリックイベントはラベルまでバブルします。そのため、ラベルのクリックイベントハンドラーが2回呼び出されます。


したがって、この問題を解決する1つの方法(OPが検出されたため)は、ラベル要素内に入力を配置しないことです。引き続き2つのクリックイベントがありますが、2番目のクリックイベントは入力からラベルにバブルアップしません。

入力がラベル内にない場合、ラベルの「for」属性を使用して、ラベルを入力に関連付けることができます。 「for」属性は、入力の「id」値に設定する必要があります。

<input type="checkbox" id="1" />
<label for="1">demo1</label>

別の解決策は、イベントが入力からバブリングするのを停止することです。

$('#test :checkbox').on('click', function(event) {
    event.stopPropagation();
});

$('#test label').on('click', function() {
    alert('clicked');
});

次に、選択された回答に表示されるソリューションがあります。これは、入力からバブルアップしたときにラベルのクリックハンドラーがイベントを無視するようにすることです。私はこのように書くのが好きです:

$('#test label').on('click', function(event) {
    if (event.target == this) {
        alert('clicked');
    }
});
3
John S

ラベルでpreventDefaultを使用し、チェックボックスでstopPropagationを使用する必要があります。

http://jsfiddle.net/uUZyn/5/

コード:

$(document).ready(function () {

    $('#test label').on('click', function (event) {
      event.preventDefault();        
      alert('clicked label');
      var ele = $(this).find('input');
    if(ele.is(':checked')){
      ele.prop('checked', false);        
    }else{
      ele.prop('checked', true);
    }
  });

  $('#test :checkbox').on('click', function (event) {
    event.stopPropagation();
    alert('clicked checkbox');
  });
});

このようにして、@ t.nieseが説明する動作を回避します

前の回答に感謝します、私はそれらなしでは理解できません:D。

更新

T.nieseが指摘しているように、私はこの動作で更新した答えを以下に示します。

http://jsfiddle.net/uUZyn/6/

PreventDefault XDを使用した後、チェック動作を追加しました。

1
Chococroc

ラベルをクリックすると2つの別々のクリックイベントがトリガーされるという同じ問題に遭遇しました。入力にname属性を追加し、ラベルにfor属性を追加することで、自分で問題を解決できました。

例えば:

<div id="test">
    <label for="checkbox1">
        <input type="checkbox" name="checkbox1" id="1" />demo1</label>
    <label for="checkbox2">
        <input type="checkbox" name="checkbox2" id="2" />demo2</label>
    <label for="checkbox3">
        <input type="checkbox" name="checkbox3" id="3" />demo3</label>
 </div>

JavaScriptは必要ありません。

0
Will Hitchcock

これは主に、子要素Yを持つX要素に対して「クリック」をトリガーし、ユーザーがYをクリックしたときに発生します。

実際にクリックされた要素からバブルされたイベントは、望ましくないイベントです。

この二重トリガーを回避するには、2つのオプションがあります...

1)$( 'selector')。triggerHandler( 'any_standard_event_name')を使用-ここでは、標準イベントとは、「クリック」、「変更」、「ホバー」などを意味します(このオプションは試したことがない)

2)カスタムイベント名を使用します。例えば。 $( 'selector')。trigger( 'my.click');

http://api.jquery.com/trigger/ で詳細を読む

0
EGL 2-101

私の場合とマテリアルデザインのmdボタンを使用しているという事実については、上記の提案はうまく機能しませんでした。これは、Androidで指を押す領域のフットプリントを劇的に削減したためです。言うまでもなく、たった2つのtagNameの代わりに、3つ以上(BUTTON、SPAN、またはMD-ICON)を取得します。また、Ariaのバージョンを変更するためのWebの他の場所での提案も役に立たなかった。 ng-infinate-scrollのヘルプドキュメントで最初にjqueryをロードするように指示されていても、angular.jsの前にjqueryをロードしていたという問題が見つかりました。とにかく、angular ng-infinate-scrollが動作を停止した後にjqueryをロードしようとすると、ng-infinate-scroll(非安定)バージョン1.2.0の最新バージョンをダウンロードし、これで、angular.jsの後にjqueryを読み込むことができ、無限スクロールが機能し、ng-clickの複数回の起動に関する問題はすべてなくなりました。

0
Helzgate

私の要素もお互いを包みました。

だから私はこのソリューションに簡単なCSSトリックを使用しました:

.off{
   pointer-events:none;
}
0
ivahidmontazer