如何使JavaScript事件处理程序首先执行?

4

我有一个页面,使用jQuery和parsley插件进行表单验证和提交。以下是表单的事件处理程序:

$('#formid').parsley().on('form:submit', function(event) {
    //handle form submit
});

我有另一个纯JavaScript监听器函数需要在表单提交时执行。以下是代码片段:

document.getElementById("formid").addEventListener("submit",function(e){
   //Some code to be executed after form submit
});

我有一个要求,不使用jQuery来完成上述功能。

现在的问题是,parsley通过使用event.stopImmediatePropagation();阻止了事件沿着线路流动。

因此,第二个事件处理程序没有被执行。有没有办法让我的纯JavaScript处理程序先执行?我找到了这个jQuery解决方案来绑定一个事件处理程序,但我需要纯JavaScript解决方案。非常感谢您的帮助。

更新: 这里是我问题的JSFiddle


你的问题必须完整地包含在问题中,而不仅仅是链接。请使用 Stack Snippets(<> 工具栏按钮)代替 jsFiddle,在可运行的演示中放置展示问题所需的全部代码。 - T.J. Crowder
我去将你的fiddle复制到你的问题中,作为一个Stack Snippet,结果发现你被jsFiddle的“惊人默认”绊倒了,它会将所有内容都包裹在window.onload = function() { /*your code here*/};的包装器中。如果你使用选项关闭这个包装器(这是一个非常愚蠢的默认设置),那么你在我的答案中遇到的问题就会消失。 - T.J. Crowder
你是对的!谢谢。如果我改成onDOMReady,代码就能正常工作。但在我的情况下,我无法控制它,因为我的代码位于链接到HTML页面头部的外部JavaScript文件中。 parsley jQuery 代码在HTML主体内的脚本标签中。所以这里无法控制顺序。 - Sathish Jayaram
将引用外部文件的script标签放在head中通常不是一个好主意(除非您使用asyncdefer),您不能移动它吗? - T.J. Crowder
我将我的代码作为外部JS文件并在页面的head标签中使用async属性。不幸的是,我无法更改这一点。我的代码必须在外部文件中。 - Sathish Jayaram
问题不在于外部文件部分,而是缺乏对代码运行时间的控制。不幸的是,如果不能确保它在Parsley代码之前运行,就会陷入困境。:-| - T.J. Crowder
3个回答

4
唯一的方法是确保在jQuery处理程序之前添加addEventListener处理程序。jQuery将使用addEventListener添加其事件处理程序(此时,它将为该元素上的所有处理程序使用单个处理程序),并且由于使用addEventListener添加的处理程序按照添加顺序进行处理,因此浏览器将首先执行您的非jQuery处理程序。
示例:

// The first addEventListener handler -- does get called
document.getElementById("the-button").addEventListener("click", function () {
    console.log("first addEventListener handler called");
}, false);

// The jQuery handler that stops immediate propagation
$("#the-button").on("click", function (e) {
    console.log("jQuery handler called");
    e.stopImmediatePropagation();
});

// The second addEventListener handler -- doesn't get called
document.getElementById("the-button").addEventListener("click", function () {
    console.log("this message won't be output");
}, false);
<input type="button" id="the-button" value="Click Me">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


谢谢你提供的解决方案。但是对我没有用。我在 parsley 监听器之前添加了我的监听器,但控制权仍然转移到 parsley。你有什么建议或者需要注意的地方吗? - Sathish Jayaram
@SathishJayaram:你能为此创建一个 [mcve] 吗?我很难相信你首先使用 addEventListener 注册的处理程序会在 jQuery 处理程序之后触发。如果是 attachEvent(旧的 Microsoft 东西),那就不同了(它的工作方式相反),但 addEventListener 明确按上述描述工作。 - T.J. Crowder
@Crowder,请查看我更新后的问题,并附上了 fiddle 链接。 - Sathish Jayaram

3

是的,你可以这样做。在addEventListener函数中使用布尔值true作为第三个参数,像下面这样绑定处理程序,它会在事件的捕获阶段绑定处理程序。了解更多有关事件捕获和冒泡阶段的信息,请参见此处

document.getElementById("formid").addEventListener("submit",function(e){
   //Some code to be executed after form submit
}, true);

-1
希望这能有所帮助。 第一种方法 我不知道这是否有效,请尝试刷新您的传播事件:
var refEvent = event.originalEvent;
refEvent.cancelBubble = false;
refEvent.defaultPrevented = false;
refEvent.returnValue = true;
refEvent.timeStamp = (new Date()).getTime();

if (event.target.dispatchEvent){
    event.target.dispatchEvent(refEvent);
} else if (event.target.fireEvent) {
    event.target.fireEvent(refEvent);
}

然后,在您的处理程序执行后,您可以再次添加event.stopPropagation();以停止传播。

第二种方法

//监听器

var stoped = false;
if(stoped){
    event.stopPropagation();
}

//处理程序

var stoped = true

来源:如何在jQuery中撤销event.stopPropagation?


一个痛点是页面是外部的。所以我不应该修改 parsley 函数,第二种方法不适合我的情况。我没有完全理解第一种方法,refEvent 指向什么? - Sathish Jayaram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接