Почему при вызове event.preventDefault() переключается флажок /radioobutton с ошибкой JavaScript?
Рассмотрим этот пример кода:
<span>
<input type="checkbox">
</span>
$('span').click(function(e) {
e.preventDefault();
$(':checkbox')[0].checked = true;
});
Fiddle
Насколько мне известно, это должно произойти:
-
preventDefault()
должен помешать проверке флажка по умолчанию браузера, даже если обработчик события указан выше в иерархии DOM. Эта часть работает правильно.
- Настройка
.checked = true
должна работать, как я полагаю, она должна быть независимой от действия браузера по умолчанию для события, которое я отменил. Эта часть кажется ошибочной, как будто preventDefault()
влияет на нее - удалите preventDefault()
и она работает по назначению.
Какова фактическая причина, по которой флажок остается неизменным?
Я тестировал на Chrome 33 и Firefox 27, поэтому это не похоже на ошибку браузера.
Этот вопрос в основном объясняется любопытством расширить мои знания модели DOM/Event. Мне не нужны обходные пути, но я хочу знать, почему этот пример не работает.
Ответы
Ответ 1
Учитывая ваш HTML:
<span>
<input type="checkbox">
</span>
и ваш код:
$('span').click(function(e) {
e.preventDefault();
$(':checkbox')[0].checked = true;
});
Событие барботажа является вашей проблемой здесь.
При нажатии checkbox
событие click распространяется на span
. e.preventDefault()
- это вызов объекта события, распространяемого из checkbox
.
Следовательно, preventDefault()
выполняется против самого checkbox
, предотвращая его проверку.
Событие click checkbox
отменяется с помощью preventDefault
, оно будет отменено до завершения потока событий. (См. Нижнюю часть ответа для получения более подробной информации об этом)
Если вы применяете некоторый стиль к диапазону, вы заметите, что щелчок по checkbox
ваш код работает так, как ожидалось, но нажатие на checkbox
само реплицирует вашу проблему из-за вышеупомянутого.
DEMO - Оригинальные стили Fiddle+. Нажатие span
в порядке, checkbox
не
В соответствии с документацией MDN на preventDefault():
Вызов preventDefault
в течение любого этапа потока событий отменяет событие, означающее, что любое действие по умолчанию, обычно принимаемое реализация в результате события не произойдет.
DOM Level 2 Spec также отмечает:
Если событие отменено, метод preventDefault
используется для означает, что событие должно быть отменено, что означает любое действие по умолчанию обычно принимаемый реализацией в результате мероприятия, не будет происходят. Если на любом этапе потока событий метод preventDefault называется событием отменено.
DOM Level 3 Events Spec в примере 5:
Действие по умолчанию, связанное с событием click
в <input type="checkbox">
, переключает значение атрибута checked
IDL этого элемента. Если действие события по умолчанию click
отменено, значение возвращается в прежнее состояние.
Ответ 2
Обтекание части кода в setTimeout
делает трюк, как вы можете видеть здесь http://jsfiddle.net/y7C77/
$('span').click(function(e) {
e.preventDefault();
setTimeout(function () {
$('input').prop('checked', true);
}, 1);
});
preventDefault()
отменяет действие по умолчанию, и я думаю, что он может отменить его, даже если вы вручную сделаете то, что сделает браузер (в этом случае: изменение свойства checked
).
Ответ 3
Вам нужно preventDefault
как click
, так и mouseup
и установить флажок mouseup
попробовать:
$('span').click(function(e) {
e.preventDefault();
}).mouseup(function(e){
e.preventDefault();
$(':checkbox')[0].checked = true;
});
Ответ 4
Это ожидаемое поведение, которое я чувствую с тех пор, когда вы говорите event.preventDefault(), вы поручаете браузеру не делать никаких операций над ним в этом случае. Таким образом, даже после утверждения, когда вы явно проверяете флажок, браузер не будет выполнять никаких операций с ним.
Мы можем видеть разницу, когда я меняю событие следующим образом:
$('span').click(function(e) {
e.preventDefault();
//$(':checkbox')[0].checked = true;
setTimeout(function(){$(':checkbox')[0].checked = true;});
});
Используя тайм-аут, мы меняем проверяемое свойство вне события, поэтому его проверили.