使用 div 包装 ASP.NET 网络表单会导致双重异步回发,但仅使用 jQuery,而不是正常的 DOM。为什么?
Wrapping ASP.NET web form with div causes double async postback, but only with jQuery, not normal DOM. Why?
为什么会这样?
- 采用带有单个 UpdatePanel 和按钮的普通 ASP.NET Web 表单。
- 在 ASP.NET 客户端 pageLoad 事件便利函数中(如果愿意,可以使用 jQuery DOM 准备好)将表单元素包装在新创建的 div 元素中使用 jQuery.
- 单击该按钮并注意 发送了两个异步 (xhr) post-backs(使用 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>
(我正在使用针对 .NET Framework 4.5.2 和 jQuery 1.7.1 的普通 web.config 文件。我能够在 Firefox 40.0.3 中重现此文件,Chrome 45.0.2454.85 和 IE 11。)
现在请注意,如果您注释掉 jQuery 行并取消注释 DOM-only 行,则只会发送一个 postback。
此外,如果您在页面加载之前将表单标记包装在 div 中(即在静态 HTML 中),它可以正常工作(没有双重 postback。)
我为什么要关心这个 matter/why?许多 jQuery 插件(例如 jPanelMenu)将 body 标签(或大部分)的全部内容包装在 div 中以确保相对定位的祖先。
因此,正如经常发生的那样,在将正确的问题与尽可能完整和简洁的演示代码放在一起的过程中,我相信我找到了答案。
我发现 如果我将 jQuery 升级到 1.9.0,问题就会消失。但是根据他们的文档,1.9.0 中的 many changes happened at 1.9.0 that could potentially break old plugins (which my project has several of.) I have a feeling that this problem is related to this change:
Loading and running scripts inside HTML content
Prior to 1.9, any HTML-accepting method (e.g., $(), .append(), or
.wrap()) executed any scripts in the HTML and removed them from the
document to prevent them from being executed again. This still broke
in situations where a script might be removed and reinserted into the
document using methods such as .wrap(). As of 1.9, scripts inserted
into a document are executed, but left in the document and tagged as
already executed so they won't be executed again even if they are
removed and reinserted.
每个带有 ScriptManager/UpdatePanel 控件的 ASP.NET Web 表单都有 WebResource.axd 和 ScriptResource.axd <script>
标签插入靠近表单元素内容的底部。这些提供了客户端 AJAX 框架。我相信 jQuery 在将表单节点附加到新的 div 节点时会重新加载这些脚本,因此会复制回发事件处理程序。我现在唯一的问题是为什么这对我来说如此难以察觉。我没有看到任何附加的事件处理程序,也没有看到脚本的额外查找(甚至缓存)。但这是一个单独的问题... :)
为什么会这样?
- 采用带有单个 UpdatePanel 和按钮的普通 ASP.NET Web 表单。
- 在 ASP.NET 客户端 pageLoad 事件便利函数中(如果愿意,可以使用 jQuery DOM 准备好)将表单元素包装在新创建的 div 元素中使用 jQuery.
- 单击该按钮并注意 发送了两个异步 (xhr) post-backs(使用 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>
(我正在使用针对 .NET Framework 4.5.2 和 jQuery 1.7.1 的普通 web.config 文件。我能够在 Firefox 40.0.3 中重现此文件,Chrome 45.0.2454.85 和 IE 11。)
现在请注意,如果您注释掉 jQuery 行并取消注释 DOM-only 行,则只会发送一个 postback。
此外,如果您在页面加载之前将表单标记包装在 div 中(即在静态 HTML 中),它可以正常工作(没有双重 postback。)
我为什么要关心这个 matter/why?许多 jQuery 插件(例如 jPanelMenu)将 body 标签(或大部分)的全部内容包装在 div 中以确保相对定位的祖先。
因此,正如经常发生的那样,在将正确的问题与尽可能完整和简洁的演示代码放在一起的过程中,我相信我找到了答案。
我发现 如果我将 jQuery 升级到 1.9.0,问题就会消失。但是根据他们的文档,1.9.0 中的 many changes happened at 1.9.0 that could potentially break old plugins (which my project has several of.) I have a feeling that this problem is related to this change:
Loading and running scripts inside HTML content
Prior to 1.9, any HTML-accepting method (e.g., $(), .append(), or .wrap()) executed any scripts in the HTML and removed them from the document to prevent them from being executed again. This still broke in situations where a script might be removed and reinserted into the document using methods such as .wrap(). As of 1.9, scripts inserted into a document are executed, but left in the document and tagged as already executed so they won't be executed again even if they are removed and reinserted.
每个带有 ScriptManager/UpdatePanel 控件的 ASP.NET Web 表单都有 WebResource.axd 和 ScriptResource.axd <script>
标签插入靠近表单元素内容的底部。这些提供了客户端 AJAX 框架。我相信 jQuery 在将表单节点附加到新的 div 节点时会重新加载这些脚本,因此会复制回发事件处理程序。我现在唯一的问题是为什么这对我来说如此难以察觉。我没有看到任何附加的事件处理程序,也没有看到脚本的额外查找(甚至缓存)。但这是一个单独的问题... :)