为什么会这样?
- 以普通ASP为例。. NET Web表单与单个UpdatePanel和按钮。
- 在ASP。. NET客户端pageLoad事件方便函数(如果你喜欢使用jQuery DOM ready)使用jQuery在新创建的div元素中包装表单元素。
- 点击按钮,注意两个异步(xhr)回发被发送(使用F12浏览器开发工具中的Net选项卡来查看它们)。
下面是重现这个问题的一些示例代码:
<%@ Language="C#" %>
<!DOCTYPE html>
<html>
<head><title>Double async postback when form element wrapped in new div after page load</title></head>
<body>
<form id="frmTest" runat="server">
<asp:ScriptManager ID="smTest" runat="server" ScriptMode="Release" />
<asp:UpdatePanel ID="upTest" runat="server">
<ContentTemplate>
<asp:Button ID="btnTest" runat="server" Text="Test Postback"/>
</ContentTemplate>
</asp:UpdatePanel>
</form>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
function pageLoad() {
// jQuery:
$("<div></div>").insertBefore("form").append($("form"));
// DOM-only:
//document.body.insertBefore(document.createElement("div"), document.forms[0]).appendChild(document.forms[0]);
}
</script>
</body>
</html>
(我正在使用一个普通的web。. net Framework 4.5.2和jQuery 1.7.1的配置文件。我能够在Firefox 40.0.3, Chrome 45.0.2454.85和IE 11中复制此内容。
现在请注意,如果您注释掉jQuery行并取消只注释dom行,则只发送一次回发。
另外,如果你在页面加载之前(即在静态HTML中)将表单标签包装在div中,它会工作得很好(没有双重回发)
为什么这很重要/为什么我关心?许多jQuery插件(如jPanelMenu)将body标签的全部(或大部分)内容包装在一个div中,以确保有一个相对定位的祖先。
因此,正如经常发生的那样,在将适当的问题与尽可能完整和简洁的演示代码组合在一起的过程中,我相信我找到了答案。
我发现如果我将jQuery升级到1.9.0,问题就消失了。但是根据他们的文档,在1.9.0中发生了许多变化,可能会破坏旧的插件(我的项目中有几个插件)。我有一种感觉,这个问题与1.9.0中的这个变化有关:
在HTML内容中加载和运行脚本
在1.9之前,任何接受html的方法(例如$(),.append(),或.wrap())执行HTML中的任何脚本,并将它们从文档以防止它们再次执行。这个还是坏了在脚本可能被删除并重新插入到使用.wrap()等方法编写文档。从1.9开始,脚本插入到文档中执行,但留在文档中并标记为已经执行了,所以即使它们被执行了,也不会再次执行删除并重新插入。
每一个ASP。. NET Web表单与ScriptManager/UpdatePanel控件有这些WebResource。axd和ScriptResource。在表单元素内容的底部插入<script>
标记。它们提供客户端AJAX框架。我认为,jQuery在将表单节点附加到新的div节点时重新加载了这些脚本,从而复制了回发事件处理程序。我现在唯一的问题是为什么我这么难以察觉。我没有看到附加任何额外的事件处理程序,也没有看到额外的脚本查找(甚至缓存)。但这是另一个问题……:)