【问题标题】:Why does preventDefault on checkbox click event returns true for the checked attribute?为什么复选框单击事件上的 preventDefault 为选中的属性返回 true?
【发布时间】:2015-08-06 05:41:15
【问题描述】:

我只是好奇,需要对以下情况进行一些解释。

假设我有一个复选框类型的输入元素,并附加了一个事件监听器,用于监听点击事件。我阻止复选框的默认行为并记录复选框的选中状态,该状态将始终返回 true。

复选框的视觉表示告诉我它没有被选中。所以我会假设检查状态会返回假。我确信这一定是愚蠢的,我在这里肯定误解了一些东西。有趣的是,我也在记录事件本身。在目标属性内部,checked 属性设置为 false,正如我所预料的那样。

据我了解,prevent default 会在不停止传播的情况下取消事件,那么这里到底发生了什么?

如果有人能在这方面启发我,那就太好了。这是一个例子。

var checkbox = document.getElementsByTagName('input')[0],
    output = document.getElementById('output');

checkbox.addEventListener('click', function(evt) {
  evt.preventDefault();
  output.innerHTML = "Checkbox checked attribute is " + this.checked;
  console.log(this.checked, evt.target.checked);
  console.log(evt);
}, false);
<input type="checkbox" id="my-checkbox" />
<label for="my-checkbox">Checkbox with preventDefault().</label>
<div id="output"></div>

【问题讨论】:

  • 我不确定,但似乎事件的默认操作在冒泡停止后实际上被取消了,因为如果您记录复选框的选中属性,以及事件的阶段在父元素中,您会注意到它仍然是正确的(并且阶段是 3,这意味着冒泡)。它保持true 直到窗口,然后,我假设preventDefault() 实际上阻止了默认操作,将其设置为false:jsfiddle.net/j52ggg7x
  • 这也可能有用:jsfiddle.net/j52ggg7x/1,超时为 0(将超时功能推到“结束”),检查值将为 false,eventPhase 将为 0 .
  • 感谢阿方索的例子。那么这是否意味着在冒泡阶段的最外层对象(在本例中为窗口对象)阻止了默认行为?
  • 会这样做,只需要再等 8 个小时,我就可以开始一场比赛了。 :-)
  • @Liam 感谢 Liam,即使感觉很奇怪,这也可能是预期的行为。这个 bug 已经很老了,所以既然什么都没有改变,那实际上可能就是它的设计方式。但如果是这样,那一定是有原因的,我很想理解它。 ;-)

标签: javascript checkbox


【解决方案1】:

实际上,click 处理程序中的checked 值的结果是依赖于实现

正如我在几个浏览器中测试的那样,Chrome/Firefox/Safari/Opera 在这种情况下总是会返回 true,但是如果你一直点击该复选框元素,IE/Edge 的行为会有点奇怪。

我在规范中找到了这一段,这可能是对这种不一致的解释:

注意:在处理类型属性值为“radio”或“checkbox”的输入元素上的点击事件期间,某些实现可能会在事件正在文档中发送。如果事件的默认动作被取消,则属性的值可能会被更改回其原始值。这意味着在处理点击事件期间该属性的值取决于实现。

但是当我去掉preventDefault语句后,在IE/Edge中的结果与其他浏览器一致,让我很困惑。

所以我认为这不是 IE/Edge 的预期行为……因此我提交了a bug on Microsoft Connect


毕竟,如果我们假设 Chrome 的行为符合标准,那么以下可能是一个合适的解释:

根据HTML Specinput[type=checkbox] 元素的检查性在取消激活过程中恢复,该过程在根据Activation 部分的事件处理程序之后。所以在事件处理程序的执行过程中,元素的检查状态还没有恢复。

(规范没有明确声明取消激活步骤必须在所有事件处理程序之后进行;但很容易推断,否则无法确定事件的取消状态)

【讨论】:

    【解决方案2】:

    根据 w3schools 的“preventDefault() 方法取消事件,如果它是可取消的,这意味着属于该事件的默认操作不会发生。”点击事件是可取消的(您可以像这样检查它console.log("cancelable?"+ evt.cancelable);。 因此,据我了解,复选框对象的单击事件的默认行为是读取复选框的当前状态并在真假之间交替,从而将其状态更改为选中和未选中。简而言之,默认行为是切换;因此, preventDefault() 会取消该行为。

    关于复选框checked = true; unchecked = false。如果您尝试逐步调试并遵循 eventListener,您将看到,一旦您进入它即使在踩到 evt.preventDefault() 因此,当您调用 console.log(this.checked, evt.target.checked); 时,编译器您的框已被“选中”,只有在 eventListener 完成执行时,复选框才会返回“未选中”状态。 由此我可以得出结论,如果复选框 preventDefault() 在所有调用之后实际上最后被激活(执行)事件监听器被执行

    【讨论】:

    • 谢谢,不胜感激。 Alfonso 也指出了你的意思。事实上,click 事件必须在最顶层的事件目标 event-click 上调度,而不是 mousedown 事件,它会立即调度,只有click 事件会恢复当默认值被阻止 default-cancel 时,检查值到它以前的状态。你能引用规格吗,所以我可以例外。也许也指出鼠标事件顺序。谢谢。
    • 您的解释与事件激活(开始)的事实更相关。如果您按下鼠标键但不释放它,在单击事件中,函数将不会开始执行。而 alfonoso 建议的是关于冒泡和捕获,这与事件 FLOW 相关。 HTML 元素相互嵌套,当您单击一个元素(复选框)时,您也在单击其父元素(body->html->document->window),这意味着单击复选框可能会影响其父元素和后代元素。 Alfonso 建议在达到某个元素之前不要激活 preventDefault。
    • 我个人的看法是,复选框的这种行为可能与在事件对象上调用 preventDefault() 而不是在单击对象上(不是在复选框上)这一事实有关。但是我没有 100% 的把握(这需要更深入的研究),这就是为什么我没有将它包含在我的答案中。
    • 这就是我在评论中想说的。它与复选框无关,而是与单击事件本身有关。使用 mousedown 或 mouseup 尝试相同的操作。与复选框有关的唯一关系是只有单击事件才会恢复复选框选中状态。但是在冒泡完成一直到窗口对象之后进行调度。
    • 我不认为它与冒泡有关,我通过启用/禁用代码中的冒泡来检查它,你会遇到同样的问题。此外,在某些情况下 preventDefault() 可能会停止冒泡。所以我的观点是:事件是mouseup还是mousedown都没有关系,甚至是click还是touch事件,或者任何其他可取消的事件都无关紧要......主要是EVENT.preventDefault()是在事件对象上调用的函数。事件对象提供有关特定事件的信息(属性)并传递给事件处理程序,问题是事件处理程序在什么时候应用这些属性。
    猜你喜欢
    • 1970-01-01
    • 2011-02-16
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多