jQuery.change + inline onchange fn()导致fn执行两次

发布这个即使我找到了答案和解决方法,希望它能帮助别人。

基本上,当使用IE8并更改元素的值时, jQuery.change挂钩到它并且内联onchange定义, onchange中 的代码执行两次

我们在使用jQuery 1.4.2AutoPostBack = true控件的ASP.NET(3.5或4.0无关紧要)项目中遇到了这个问题,这些控件使用onchange =“__ doPostBack(…)”属性进行渲染,导致回发发生两次用于单个用户启动的控制状态更改。 (微软真的需要摆脱浏览器业务 – 他们很糟糕。)

为了演示这个问题,我创建了一个空的网站项目并添加了一个aspx页面,下面是完整的代码+标记。 重要的元素是对jQuery的SCRIPT引用,连接control.change处理程序的$ document.ready,以及单独的autopostback控件(我已经validation它与TextBox和DropDownList一起发生)。 请注意,页面上不存在其他控件 – 没有AJAXToolkit控件,如UpdatePanels,也没有带有空SRC属性的IMG,这是一个长期存在的错误,也会触发双回发。

  protected void Page_Init(object sender, EventArgs e) { Trace.Write(String.Format("IsPostBack = {0}; PostbackControl = {1}", IsPostBack.ToString(), Page.Request.Params.Get("__EVENTTARGET"))); } protected void txtTest_TextChanged(object sender, EventArgs e) { Trace.Write(String.Format("Name = {0}", txtTest.Text)); }    Demo of jQuery + AutoPostBack double postback problem   
$(document).ready(function () { $('#').change(function () { alert('Double postback coming up!'); }) });

您可以通过在Page_Init中设置断点,启用IE脚本调试并单步执行javascript以查看onchange执行两次,或者通过启用跟踪并在trace.axd中查看生成的两个请求来观察双回发。

你把什么放在jQuery.change处理程序中并不重要; 删除警报或让它返回bool甚至使处理程序完全为空对double onchange / postback行为没有影响。

无论你是否在标记中以声明方式或在代码中强制性地连接服务器端TextChanged事件处理程序,也会发生这种情况(显然你不应该同时执行这两者或者你自己会导致双重回发)。

尽管ASP.NET生成的onchange =“__ doPostBack(…)”正在执行两次,但jQuery.change处理程序只执行一次因为警报只显示一次。 偶尔(可能是5个或6个中的1个),onchange只会触发一次,回发一次,因此该错误似乎并不一致。

更糟糕的是,在我们第一次遇到这种行为的实际生产项目中,有时当它发布双重post时,一个请求的IsPostBack = true而另一个请求为false,导致初始化代码再次执行。 但是我无法在演示项目中重现这种行为,因此它可能是与此交互的单独问题。

如果您注释掉jQuery.change,它将恢复为正常的所需单个回发行为。

我用谷歌搜索疯狂,但只能找到一个可能面临同样问题的论坛post。 只有在我确定Firefox中没有出现问题并将IE8添加到我的搜索词列表中之后,才会遇到jQuery错误报告。 http://dev.jquery.com/ticket/6310 http://dev.jquery.com/ticket/6593

解决方法(在ASP.NET中)是禁用AutoPostBack并在jQuery事件处理程序的末尾为所有必须同时运行客户端和服务器端代码的控件显式添加__doPostBack。

编辑:修复了jQuery选择器,正如meep指出的那样,缺少#。

据我所知,此问题仅限于Internet Explorer,因此如果您有此选项,请从您的应用用户中取走IE。

或者禁用AutoPostBack并在jQuery事件处理程序的末尾显式添加__doPostBack,以用于必须同时运行客户端和服务器端代码的所有控件。 如果您使用的是普通的-html控件,请不要对相同的元素使用内联onchange和jQuery.change。

或者自己破解jQuery以防止在更改挂钩时执行两次onchange。

或者等待jQuery的下一个版本,并希望问题得到解决。

微软可能永远不会解除它,因为他们继续将旧的IE6错误传播到更新的IE版本。

抛开微软,这是IE的更多jQuery的错。 这是由于jQuery尝试解决IE中change事件缺少冒泡的问题,除了自然更改事件之外,还为每个祖先元素以及目标元素调用额外的伪造更改事件。 据推测,这个bug没有被注意到,因为触发多个onchange事件通常是无害的。

(这不是答案。但是,你的问题不是问题。)