在事件冒泡阶段移除祖先

时间:2016-02-11 10:42:12

标签: javascript html javascript-events dom-manipulation event-bubbling

在以下代码中(JSFiddle here):

<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事件处理程序启动之前完成。 我在这里失明了。 jQuery必须在Chrome中做一些奇怪的麻烦事情。

跟进2:
这不是一个jQuery问题。在jQuery bug跟踪器中,我被告知内联事件处理程序不遵循与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版本相同。

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

Chromium和Firefox都没有调用$('form')安装的form.onsubmit处理程序。当$('form')。remove()调用时,提交(...)。因此,这意味着在Chromium和Firefox中调用onsubmit之前,将表单检查为已销毁(或实际销毁)。

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

在对面的Firefox中忽略按钮事件的preventDefault并将控制传递给form.onsubmit。

因此,这两个浏览器关于preventDefault和onsubmit的行为正好相反。

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

答案 2 :(得分:0)

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

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

在jQuery事件监听器中,return false等同于

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

后者应该阻止提交表单。

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

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

然后浏览器的行为方式不同(demo):

  • 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();

这会使它表现得像第二个代码。

相关问题