在 onchange 事件之前触发 onblur 事件

9
我有一个包含多个文本输入字段的大型表单。基本上,我需要处理所有字段的 onchange 事件和一些字段的 onblur 事件。当更改字段并且该字段失去焦点时,两个事件都会触发(这是正确的行为)。唯一的问题是,我希望在处理 onchange 事件之前处理 onblur 事件。
在ie和Firefox中进行了一些测试后,似乎默认行为是在触发 onblur 事件之前触发 onchange 事件。我一直在使用以下代码进行测试...
<html>

<body >
    <input type="text" value="here is a text field" onchange="console.log('Change Event!')" onblur="console.log('Blur Event!')" >

</body>
</html>

这就引出了我的问题:

  1. 看起来这种行为在所有浏览器中都是一致的,为什么onchange事件会先被触发?

  2. 由于我无法为每个输入元素处理onblur事件,有没有一种方法可以在处理onchange事件之前让onblur事件触发?


你的标签中有 jQuery。你在使用它吗?如果是,你可以通过检查处理程序内的 event.type 来以任何顺序处理事件。 - DevlshOne
3
@DevlshOne - 但是你不能改变它们被触发的顺序,只能调整其它方面。 - techfoobar
不,你不能改变顺序,但你可以按照你想要的任何顺序进行处理。 - DevlshOne
@j08691 如果不引入显著的延迟,那将是不可靠的。但是alexsh的方法使这变得不必要了。 - Asad Saeeduddin
@Richard 你的意思是这只适用于特定的浏览器? - Joel
显示剩余6条评论
2个回答

10
  1. 原因是一旦元素失去焦点(即'blur'),通常更改就完成了,因此onchange首先触发(我说通常是因为脚本仍然可以在没有用户交互的情况下更改元素)。

  2. 对于那些需要优先处理onblur的元素,您可以禁用onchange处理程序并从onblur处理程序中触发onchange(甚至是自定义事件)。 这将确保正确的顺序,尽管它需要更多的工作。 要检测更改,可以使用该字段的状态变量。

总的来说,这种同步需求表明您正在使用的方法解决问题可能需要更多的工作,尽管有时无法避免。 如果您确定这是唯一的方法,请尝试其中一种方法!

编辑:只是为了详细说明最后一点,您将不得不遵循有关事件模型的一些假设。 您是否假定每个change事件后跟随一个blur并且否则未经处理,或者您希望处理每个change但那些跟随blur的会在onblur完成后进一步处理它们? 在任何情况下,如果要强制执行处理程序的顺序,则处理程序将需要访问公共资源(全局变量,属性等)。 是否有其他事件类型您可能想要使用? (input?)。 最后,此链接提供了有关Mozilla浏览器的change事件的一些详细信息:https://developer.mozilla.org/en-US/docs/Web/Reference/Events/change。第三个“bullet”解决了事件顺序的问题。


1
这种同步的需求表明你正在使用的方法...可能需要更多的工作。 - cfs
如果我只为那些选择元素处理onblur事件,我将失去知道字段是否已更改的能力...因此需要onchange处理程序。为每个字段创建状态变量并不是非常简单的事情。 - Joel
@Joel 由于 onchange 在前面,您可以在元素上设置一个数据属性来指示值已在 onchange 处理程序中更改,然后在 onblur 处理程序中读取和清除此属性,并根据其进行操作。 - Asad Saeeduddin
我刚刚添加了一条注释,以解决这个问题。你可以在一个单独的变量中保持状态。更干净,但更繁琐的方法是将onblur事件的处理分成两个部分:第二个部分由onchange触发,然后返回到onchange处理程序的第二个部分(虽然这可能有点过度设计)。 - alexsh

4
这是一个小技巧,虽然有些折衷,但在大多数浏览器上似乎都能起作用:
<input type="text" value="Text Input" onchange="setTimeout(function(){console.log('Change Event!')}, 0);" onblur="console.log('Blur Event!');" />

你可以在这里看到它的演示: http://jsfiddle.net/XpPhE/ 以下是关于 setTimeout(function, 0) 技巧的一些背景信息:http://javascript.info/tutorial/events-and-timing-depth 希望这可以帮到你 :)

2
我不确定这个可靠性如何。它似乎并没有保证事件处理程序会在使用setTimeout立即调度的回调之前被触发,因此您可能只是依赖于实现细节。 - Asad Saeeduddin

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