jquery .each()を使用して個々のイベントリスナーを追加するにはどうすればよいですか?

Jan 08 2021

簡単な設定があります。値が異なる2つのボタンです。jqueryの.each()関数を使用して、各ボタンの値をログに記録するだけのクリックイベントリスナーを各ボタンに追加したいと思います。しかし、どういうわけか.each()を使用すると、jqueryは前のボタンのクリックハンドラーを上書きします。これは私に2つの質問を残します:

  1. 何故ですか?
  2. 個々のイベントリスナーをjqueryオブジェクトのコレクションに追加するにはどうすればよいですか?

以下のコードを参照してください

  <html lang="en">
    
    <head>
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script>
            $(() => { $(`button[toggle]`).each((_, button) => {
                    let $toggle = $(button);
                    type = $toggle.attr("type"); value = $toggle.attr("value");
                    $toggle.on("click", () => {
                        console.log(type, value);
                    });
                });
            });
        </script>
    
    </head>
    
    <body>
        <div>
            <button toggle type="one" value="true">One</button>
            <button toggle type="two" value="false">Two</button>
        </div>
    </body>
    
    </html>

回答

1 RoryMcCrossan Jan 08 2021 at 20:14

コードの問題は、変数と変数を暗黙的に宣言しているため、スコープ内にあるためです。そのため、後続の各反復で値が上書きされ、ループの終了後に最終値のみが表示されます。typevaluewindow

これを修正するには、ループ内で変数を定義します。

$(() => { $(`button[toggle]`).each((_, button) => {
    let $toggle = $(button);
    let type = $toggle.attr("type"); let value = $toggle.attr("value");
    $toggle.on("click", () => {
      console.log(type, value);
    });
  });
});
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<div>
  <button toggle type="one" value="true">One</button>
  <button toggle type="two" value="false">Two</button>
</div>

ただしeach()ループはまったく必要ありません。同じイベントハンドラーをすべてのbutton要素にバインドし、target発生したイベントのプロパティを使用してそれらの属性にアクセスすることで、問題を修正し、コードの品質を向上させることができます。

さらに、toggleこの場合、独自の非標準属性を追加すると、UIとJSで問題が発生する可能性があることに注意してください。より良いアプローチは、クラスを使用して要素をグループ化することです。

最後に、oneおよびtwotype属性の有効な値ではありません。data代わりに属性を使用して、独自のカスタムメタデータを要素に添付します。

そうは言っても、これを試してみてください。

jQuery($ => {
  $('.toggle').on('click', e => { let $toggle = $(e.target); let type = $toggle.data("type"); 
    let value = $toggle.prop("value");
    console.log(type, value);
  });
});
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<div>
  <button class="toggle" data-type="one" value="true">One</button>
  <button class="toggle" data-type="two" value="false">Two</button>
</div>

1 prasanth Jan 08 2021 at 20:10

$(this)クリックコールバック内で使用

$(() => {
  $(`button[toggle]`).each((_, button) => { $(button).on("click", function(){
       type   = $(this).attr("type"); value = $(this).attr("value");
      console.log(type, value);
    });
  });
});
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

<button toggle type="one" value="true">One</button>
<button toggle type="two" value="false">Two</button>

また、各コールバック内で言及する必要はありません。以下のように通常の方法で呼び出すことができます

$(() => { $(`button[toggle]`).on("click", function(){
       type   = $(this).attr("type"); value = $(this).attr("value");
      console.log(type, value);
    });
});
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

<button toggle type="one" value="true">One</button>
<button toggle type="two" value="false">Two</button>

Kostas Jan 08 2021 at 20:11
  1. リスナーは$ toggleの最後の値にバインドするためです。
  2. スニペットに示されているように、新しい関数を作成して実行する。

この質問でよりよく説明されました。

<html lang="en">
    
    <head>
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script>
            $(() => {
                $(`button[toggle]`).each((_, button) => { let $toggle = $(button); type = $toggle.attr("type");
                    value = $toggle.attr("value"); $toggle.on("click", ((type, value) => {
                      return () => {
                        console.log(type, value);
                      };
                    })(type, value));
                });
            });
        </script>
    
    </head>
    
    <body>
        <div>
            <button toggle type="one" value="true">One</button>
            <button toggle type="two" value="false">Two</button>
        </div>
    </body>
    
    </html>