繁体   English   中英

在事件冒泡阶段移除祖先

[英]Removing an ancestor during the event bubbling phase

在以下代码中(此处为 JSFiddle ):

<form>
   <button>ok</button>
</form>
$(function(){
    $('form').submit(false) ;
    $('button').click(function(){ $('form').remove() }) ;
}) ;

当您单击 Google Chrome 48 中的按钮时,它会触发表单提交。
但是,如果您在 Firefox 43 中执行此操作,则不会提交表单。

在我看来,Firefox 的行为应该是正确的,但由于我对标准没有如此深入的了解,我真的不知道。

行为是错误的还是错误的?


跟进:
我刚刚发现相同的测试用例但不使用 jQuery 不会在两个浏览器中触发表单提交。

<form onsubmit="return false">
    <button onclick="form.remove()">ok</button>
</form>

这不可能是时间问题,因为 Javascript 中没有线程并发。 事件线程将始终按顺序运行,因此button事件处理程序必须在form事件处理程序启动之前完成。
我在这里瞎了。 为了在 Chrome 中发生这种情况,jQuery 必须做一些奇怪而繁琐的事情。


跟进2:
这不是 jQuery 问题。 在 jQuery 错误跟踪器中,我被告知内联事件处理程序不遵循与addEventListener附加的规范相同的规范,因此真正功能等效的代码应该是这样的:

<form>
    <button>ok</button>
</form>
<script>
document.querySelector('form').addEventListener('submit',function(){ return false }) ;
document.querySelector('button').addEventListener('click',function(evt){ evt.target.form.remove() }) ;
</script>

这确实像 jQuery 版本。

我认为它依赖于实现而不保证相同的行为

当 $('form').remove() 调用时,Chromium 和 Firefox 都不会调用由 $('form').submit(...) 安装的 form.onsubmit 处理程序。 因此,这意味着在 Chromium 和 Firefox 中调用 onsubmit 之前,表单被检查为已销毁(或确实已销毁)。

我认为 Chromium 不会检查在按下按钮发出的流程默认提交操作时标记为已销毁的表单。 但是 Chromium 会检查 preventDefault 标志,其中按钮的默认操作是表单提交。 因此可以在 $('form').remove() 之前或之后添加 event.preventDefault()。

相反,Firefox 忽略按钮按下事件的 preventDefault 并将控制权传递给 form.onsubmit。

所以这两个浏览器关于 preventDefault 和 onsubmit 的行为是完全相反的。

至于当表单被标记为销毁时表单提交的事实,可以想象软件设计在通信完成之后而不是之前实际删除对象的情况。 但在我看来,这是错误。 需要知道开发人员的想法。 他们是否知道这个错误或功能。

您的第一个代码添加了一个returnFalse jQuery 事件侦听器:

$('form').submit(false);

在 jQuery 事件侦听器中, return false相当于

event.stopPropagation();
event.preventDefault();

后者应阻止提交表单。

但是,在触发submit事件之前,您使用$.fn.remove 这不仅会从文档中删除表单,还会清除其 jQuery 数据,包括事件侦听器。

因此,当浏览器submit表单触发submit事件时,它不会被取消。

然后浏览器的行为有所不同(演示):

  • Firefox 不提交已删除的表单
  • Chrome 不关心表单是否已被删除并提交

如果您不想删除 jQuery 数据,您应该使用 vanilla-js 方法而不是$.fn.remove删除表单。


在您的第二个代码中,您取消了 vanilla-js 事件处理程序中的事件。

由于不是jQuery数据, $.fn.remove不会移除,所以submit事件被取消,表单没有提交。


在第三个代码中,您使用 vanilla-js 方法删除表单,因此不会清除其 jQuery 数据。

这无关紧要,因为submit事件侦听器也添加了 vanilla-js。

但是,该活动并未取消。 这是因为,与 vanilla-js 事件处理程序和 jQuery 事件侦听器不同,vanilla-js 事件侦听器中返回的值被完全忽略。

所以最后的结果与第一个代码中的结果相同,但它们并不等效。

如果你想使用 vanilla-js 事件监听器取消一个事件,你应该使用

event.preventDefault();

这将使其表现得像第二个代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM