0

为什么会这样?

  1. 采用带有单个 UpdatePanel 和 Button 的普通 ASP.NET Web 窗体。
  2. 在 ASP.NET 客户端 pageLoad 事件便利函数中(如果您愿意,可以使用 jQuery DOM)将表单元素包装在使用 jQuery 新创建的 div 元素中。
  3. 单击该按钮并注意发送了两个异步 (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>

(我使用的是针对 .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 行,则只会发送一个回发。

此外,如果您在页面加载之前将表单标签包装在 div 中(即在静态 HTML 中)它可以正常工作(没有双重回发。)

为什么这很重要/我为什么在乎?许多 jQuery 插件(例如jPanelMenu)将 body 标签的全部内容(或大部分)包装在一个 div 中,以确保一个相对定位的祖先。

4

1 回答 1

0

因此,正如经常发生的那样,在将一个适当的问题与尽可能完整和简洁的演示代码组合在一起的过程中,我相信我找到了答案。

我发现如果我将 jQuery 升级到 1.9.0,问题就消失了。但是根据他们的文档,在 1.9.0中发生了许多更改,这些更改可能会破坏旧插件(我的项目有几个)。我感觉这个问题与1.9.0中的这个更改有关:

在 HTML 内容中加载和运行脚本

在 1.9 之前,任何接受 HTML 的方法(例如,$()、.append() 或 .wrap())都会执行 HTML 中的任何脚本并将它们从文档中删除以防止它们再次被执行。在使用 .wrap() 等方法删除脚本并重新插入到文档中的情况下,这仍然会中断。从 1.9 开始,插入到文档中的脚本会被执行,但会留在文档中并标记为已执行,因此即使移除并重新插入它们也不会再次执行。

每个带有 ScriptManager/UpdatePanel 控件的 ASP.NET Web 表单都<script>在表单元素内容的底部附近插入了那些 WebResource.axd 和 ScriptResource.axd 标记。它们提供客户端 AJAX 框架。我相信 jQuery 在将表单节点附加到新的 div 节点时重新加载了这些脚本,因此复制了回发事件处理程序。我现在唯一的问题是为什么这对我来说如此难以察觉。我没有看到附加的任何额外事件处理程序,或脚本的额外查找(甚至缓存)。但这是一个单独的问题...... :)

于 2015-09-11T00:32:41.987 回答