Щелчок jQuery запускает обработчик событий щелчка 3 раза

Я попытался реализовать простой веб-сайт с 5 флажками.
Если пользователь нажимает флажок «Все», все остальные флажки будут отмечены или сняты в зависимости от значения флажка «Все».

$(document).ready(function() {
  $("#all").click(function(event) {
    console.info("all");
    $("input[name=vehicle]").each(function() {
      $(this).click();
    });
  });
});

function checkVehicle(event, id) {
  // console.info(event);
  console.info(id);
}
<script src = "https://code.jquery.com/jquery-3.7.1.min.js"
    integrity = "sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo = " crossorigin = "anonymous"></script>

  <input type = "checkbox" id = "all" name = "all" />
  <label for = "all">All</label>

  <input type = "checkbox" id = "car" name = "vehicle" onclick = "checkVehicle(event, 1)" />
  <label>Car</label>
  <input type = "checkbox" id = "bike" name = "vehicle" onclick = "checkVehicle(event, 2)" />
  <label>Bike</label>
  <input type = "checkbox" id = "truck" name = "vehicle" onclick = "checkVehicle(event, 3)" />
  <label>Truck</label>
  <input type = "checkbox" id = "tank" name = "vehicle" onclick = "checkVehicle(event,4)" />
  <label>Tank</label>

Проблема в том, что когда я нажимаю флажок «Все», флажок CheckVehicle для каждого другого вызывается 3 раза.
Мне интересно узнать причину такого поведения, а не то, как его исправить.

Я мог бы решить проблему, используя один из следующих методов.
Во-первых, вместо того, чтобы запускать событие щелчка по элементу jQuery, я мог бы вызвать его на элементе DOM.

$(document).ready(function() {
  $("#all").click(function(event) {
    console.info("all");
    $("input[name=vehicle]").each(function() {
      $(this)[0].click();
    });
  });
});

function checkVehicle(event, id) {
  console.info(event);
  console.info(id);
}

Во-вторых, вместо встроенной регистрации события я мог бы зарегистрировать его программно.

<!DOCTYPE html>
<html lang = "en">

<head>
  <meta charset = "UTF-8">
  <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
  <script src = "https://code.jquery.com/jquery-3.7.1.min.js"
    integrity = "sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo = " crossorigin = "anonymous"></script>
  <title>Document</title>
</head>

<body>
  <script src = "index.js"></script>

  <input type = "checkbox" id = "all" name = "all" />
  <label for = "all">All</label>

  <input type = "checkbox" id = "car" name = "vehicle" />
  <label>Car</label>
  <input type = "checkbox" id = "bike" name = "vehicle" />
  <label>Bike</label>
  <input type = "checkbox" id = "truck" name = "vehicle" />
  <label>Truck</label>
  <input type = "checkbox" id = "tank" name = "vehicle" />
  <label>Tank</label>

</html>

И вот мой index.js

$(document).ready(function() {
  $("#all").click(function(event) {
    console.info("all");
    $("input[name=vehicle]").each(function() {
      $(this).click();
    });
  });

  $("input[name=vehicle]").click(function() {
    console.info("personal");
  });

});

Почему все ярлыки имеют одинаковый for = "all" вместо фактического входного идентификатора?

Justinas 29.08.2024 11:28

@Justinas Спасибо за ваш комментарий. Убираю ненужные атрибуты в метках.

nammae88 29.08.2024 11:32

«Мне интересно узнать причину такого поведения» — у вас есть onclick = "checkVehicle(event, ...) в каждом из ваших флажков, ожидающих «все», плюс вы добавляете дополнительный обработчик кликов к каждому из них в вашем JS — и когда «все» нажимается , вы явно запускаете псевдо-щелчок по всем из них с помощью $(this).click(); в цикле, что затем, конечно же, запускает обработчики событий, которые вы к ним добавили.

C3roe 29.08.2024 11:34

Если вы не хотите, чтобы это запускало обработчики кликов на флажках, вам не следует сначала щелкать их через JS, а вместо этого манипулировать значением их свойства checked. И вместо обработчика кликов для флажков предпочтительнее обработчики change.

C3roe 29.08.2024 11:37

@Karan Извините, если мое описание недостаточно ясно. Проблема в том, что обработчик кликов для каждого флажка вызывается ровно 3 раза. Вывод журнала консоли будет (1 1 1 2 2 2 3 3 3 4 4 4). Если я изменю код как один из двух методов, которые я предложил, тогда каждый обработчик кликов будет вызываться один раз, и результат будет следующим (1 2 3 4).

nammae88 29.08.2024 11:38

@ nammae88, я понял твою точку зрения. Похоже, это связано с версией jQuery. Я пробовал использовать более старую версию с jQuery3.3.1 и старше, она работает как положено. В jQuery4.0.0 или более поздних версиях событие щелчка вызывается 3 раза.

Karan 29.08.2024 11:47

это происходит потому, что вы применили цикл ко всем $("input[name=vehicle]") и в боковом цикле вы запускаете событие щелчка

Death-is-the-real-truth 29.08.2024 11:47

вам не нужно активировать click для всех остальных флажков, вместо этого создайте свойство checked либо true, либо false

Death-is-the-real-truth 29.08.2024 11:48

@C3roe C3roe, кажется, мы неправильно поняли вопрос. Вы можете попробовать запустить фрагмент кода, и, как мы ожидаем, он должен вызвать событие щелчка для всех входов один раз. Но здесь происходит то, что код $(this).click(); вызывает соответствующие функции onclick три раза, и вы заметите вывод: вывод журнала консоли будет (1 1 1 2 2 2 3 3 3 4 4 4) вместо (1 2 3 4).

Karan 29.08.2024 12:00

Кажется, ошибка в jQuery; представлен в версии 3.4.0

trincot 29.08.2024 12:01

В частности, это ошибка в сочетании с этими встроенными обработчиками событий. Если я удалю атрибуты onclick и вместо этого добавлю обработчик кликов к этим флажкам с помощью $("input[name=vehicle]").on('click', function(){ console.info(this.id) }); - тогда щелчок по флажку «все» записывает идентификатор каждого флажка в консоль только один раз.

C3roe 29.08.2024 12:09
Как конвертировать HTML в PDF с помощью jsPDF
Как конвертировать HTML в PDF с помощью jsPDF
В этой статье мы рассмотрим, как конвертировать HTML в PDF с помощью jsPDF. Здесь мы узнаем, как конвертировать HTML в PDF с помощью javascript.
3
11
64
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Как поясняется в комментариях, если вы хотите, чтобы проверялись только свойства, вы можете сделать $("input[name=vehicle]").prop("checked", $(this).prop("checked")) без цикла, jQuery справится с этим за вас:

$(document).ready(function() {
  $("#all").click(function(event) {
    console.info("all");
    $("input[name=vehicle]").prop("checked", $(this).prop("checked"))/*.each(function() {
      $(this).click();
    });*/
  });
});

function checkVehicle(event, id) {
  // console.info(event);
  console.info(id);
}
<script src = "https://code.jquery.com/jquery-3.7.1.min.js"
    integrity = "sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo = " crossorigin = "anonymous"></script>

  <input type = "checkbox" id = "all" name = "all" />
  <label for = "all">All</label>

  <input type = "checkbox" id = "car" name = "vehicle" onclick = "checkVehicle(event, 1)" />
  <label>Car</label>
  <input type = "checkbox" id = "bike" name = "vehicle" onclick = "checkVehicle(event, 2)" />
  <label>Bike</label>
  <input type = "checkbox" id = "truck" name = "vehicle" onclick = "checkVehicle(event, 3)" />
  <label>Truck</label>
  <input type = "checkbox" id = "tank" name = "vehicle" onclick = "checkVehicle(event,4)" />
  <label>Tank</label>

Но если вам интересно, что происходит под капотом, взгляните на этот фрагмент:

$(document).ready(function() {
  $("#all").click(function(event) {
    console.info("all");
    $("input[name=vehicle]").each(function() {
      this.click();
    });
  });
});

function checkVehicle(event, id) {
  // console.info(event);
  console.info(id);
}
<script src = "https://code.jquery.com/jquery-3.7.1.min.js"
    integrity = "sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo = " crossorigin = "anonymous"></script>

  <input type = "checkbox" id = "all" name = "all" />
  <label for = "all">All</label>

  <input type = "checkbox" id = "car" name = "vehicle" onclick = "checkVehicle(event, 1)" />
  <label>Car</label>
  <input type = "checkbox" id = "bike" name = "vehicle" onclick = "checkVehicle(event, 2)" />
  <label>Bike</label>
  <input type = "checkbox" id = "truck" name = "vehicle" onclick = "checkVehicle(event, 3)" />
  <label>Truck</label>
  <input type = "checkbox" id = "tank" name = "vehicle" onclick = "checkVehicle(event,4)" />
  <label>Tank</label>

Вы заметите, что без объекта jQuery $(this) простой .click() из this будет делать то, что вы хотите. Таким образом, это явно связано с тем, что означает «это» внутри вашего обратного вызова .each(). Обратите внимание, что этот второй скрипт отменит ваши флажки, поэтому, если вы сначала вручную установили флажок, а затем щелкните все, чтобы отметить все, то тот, который вы отметили, будет снят, что вряд ли является вашим намерением. Вы можете улучшить его следующим образом:

$(document).ready(function() {
  $("#all").click(function(event) {
    console.info("all");
    $("input[name=vehicle]").each(function() {
      if (this.checked !== event.target.checked) $(this).click();
    });
  });
});

function checkVehicle(event, id) {
  // console.info(event);
  console.info(id);
}
<script src = "https://code.jquery.com/jquery-3.7.1.min.js"
    integrity = "sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo = " crossorigin = "anonymous"></script>

  <input type = "checkbox" id = "all" name = "all" />
  <label for = "all">All</label>

  <input type = "checkbox" id = "car" name = "vehicle" onclick = "checkVehicle(event, 1)" />
  <label>Car</label>
  <input type = "checkbox" id = "bike" name = "vehicle" onclick = "checkVehicle(event, 2)" />
  <label>Bike</label>
  <input type = "checkbox" id = "truck" name = "vehicle" onclick = "checkVehicle(event, 3)" />
  <label>Truck</label>
  <input type = "checkbox" id = "tank" name = "vehicle" onclick = "checkVehicle(event,4)" />
  <label>Tank</label>

Когда вы вызываете $(this).trigger('click'); внутри обработчика $("#all").click(function(event) { ... });, он имитирует событие щелчка по каждому флажку.

Вы можете попробовать установить prop значение checked, а затем запустить функцию checkVehicle

$(document).ready(function () {
   $("#all").click(function (event) {
      console.info("all");
      $("input[name=vehicle]").each(function (e) {
          $(this).prop('checked', true);
          checkVehicle(e, $(this).attr('id'));
      });
   });
});

function checkVehicle(event, id) {
   console.info(id);
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<input type = "checkbox" id = "all" name = "all" />
<label for = "all">All</label>

<input type = "checkbox" id = "car" name = "vehicle" onclick = "checkVehicle(event, 1)" />
<label>Car</label>
<input type = "checkbox" id = "bike" name = "vehicle" onclick = "checkVehicle(event, 2)" />
<label>Bike</label>
<input type = "checkbox" id = "truck" name = "vehicle" onclick = "checkVehicle(event, 3)" />
<label>Truck</label>
<input type = "checkbox" id = "tank" name = "vehicle" onclick = "checkVehicle(event,4)" />
<label>Tank</label>
Ответ принят как подходящий

Вы столкнулись с ошибкой, о которой сообщалось в 2019 году, выпуск № 4493:

Когда calling $(...).click() на входе флажка, для которого определено свойство onclick, его обратный вызов вызывается три раза.

Судя по всему такое поведение появилось в версии 3.4.0.

Ответ члена команды jQuery был:

Встроенные обработчики событий общеизвестно ненадежны, и в результате у нас практически нет тестового покрытия для них. По этой причине они в нашем списке , которые нельзя исправить .

А в списке исправлений есть:

Встроенные обработчики событий

В общем, со встроенными обработчиками событий невероятно сложно работать, и их не следует использовать. Почти во всех случаях проблемы, связанные со встроенными обработчиками событий, выходят за рамки рассмотрения. Встроенные обработчики ведут себя не так, как обработчики событий, добавленные с помощью стандартного метода DOM addEventListener.

Итак, вот оно. Это известная ошибка, и она не будет исправлена.

Другие вопросы по теме