关于javascript:jQuery $(document).ready和UpdatePanels?

jQuery $(document).ready and UpdatePanels?

我使用jquery在updatepanel中的元素上连接一些mouseover效果。这些事件在$(document).ready中受到约束。例如:

1
2
3
4
5
$(function() {    
    $('div._Foo').bind("mouseover", function(e) {
        // Do something exciting
    });    
});

当然,这在第一次加载页面时可以正常工作,但是当updatepanel进行部分页面更新时,它不会运行,并且mouseover效果在updatepanel中不再起作用。

在jquery中,建议的方法是什么?不仅在第一次页面加载时,而且每次更新面板触发部分页面更新时,都要使用哪种方法?我应该使用ASP.NET AJAX生命周期而不是$(document).ready吗?


更新面板完全替换更新上更新面板的内容。这意味着您订阅的那些事件将不再订阅,因为该更新面板中有新的元素。

我所做的工作就是在每次更新之后重新订阅我需要的事件。我使用$(document).ready()进行初始加载,然后使用Microsoft的PageRequestManager(如果页面上有更新面板,则可用)重新订阅每个更新。

1
2
3
4
5
6
7
8
9
$(document).ready(function() {
    // bind your jQuery events here initially
});

var prm = Sys.WebForms.PageRequestManager.getInstance();

prm.add_endRequest(function() {
    // re-bind your jQuery events here
});

PageRequestManager是一个javascript对象,如果页面上有更新面板,它将自动可用。只要updatepanel在页面上,就不需要执行上述代码以外的任何操作来使用它。

如果需要更详细的控制,此事件将传递类似于.NET事件如何传递参数(sender, eventArgs)的参数,因此您可以查看引发事件的内容,并且仅在需要时重新绑定。

以下是来自Microsoft:msdn.microsoft.com/…/bb383810.aspx的文档的最新版本

根据需要,您可能有一个更好的选择,那就是使用jquery的.on()。这些方法比在每次更新时重新订阅DOM元素更有效。但是,在使用此方法之前,请阅读所有文档,因为它可能满足您的需要,也可能不满足您的需要。有很多jquery插件不适合重构为使用.delegate().on(),所以在这些情况下,您最好重新订阅。


1
2
3
4
5
6
7
8
9
10
<script type="text/javascript">

        function BindEvents() {
            $(document).ready(function() {
                $(".tr-base").mouseover(function() {
                    $(this).toggleClass("trHover");
                }).mouseout(function() {
                    $(this).removeClass("trHover");
                });
         }

将要更新的区域。

1
2
3
4
5
6
7
8
<asp:UpdatePanel...
<ContentTemplate
     <script type="text/javascript">
                    Sys.Application.add_load(BindEvents);
     
 *// Staff*
</ContentTemplate>
    </asp:UpdatePanel>


在updatepanel中使用jquery的用户控件

这不是问题的直接答案,但我通过阅读我在这里找到的答案,把这个解决方案放在一起,我认为有人可能会发现它是有用的。

我试图在用户控件内使用jquery文本区域限制器。这很棘手,因为用户控件运行在UpdatePanel内部,并且在回调时丢失了绑定。

如果这只是一页,这里的答案将直接应用。但是,用户控件不能直接访问head标签,也不能像某些答案假设的那样直接访问updatepanel。

最后我把这个脚本块放到了我的用户控件标记的顶部。对于初始绑定,它使用$(document).ready,然后使用prm.add_endrequest。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script type="text/javascript">
    function BindControlEvents() {
        //jQuery is wrapped in BindEvents function so it can be re-bound after each callback.
        //Your code would replace the following line:
            $('#<%= TextProtocolDrugInstructions.ClientID %>').limit('100', '#charsLeft_Instructions');            
    }

    //Initial bind
    $(document).ready(function () {
        BindControlEvents();
    });

    //Re-bind for callbacks
    var prm = Sys.WebForms.PageRequestManager.getInstance();

    prm.add_endRequest(function() {
        BindControlEvents();
    });

所以…只是想有人可能想知道这是可行的。


升级到jquery 1.3并使用:

1
2
3
4
5
6
7
$(function() {

    $('div._Foo').live("mouseover", function(e) {
        // Do something exciting
    });

});

注意:Live适用于大多数活动,但并非所有活动。文档中有一个完整的列表。


您也可以尝试:

1
2
3
4
5
6
7
8
9
10
11
12
    <ContentTemplate>

        <script type="text/javascript" language="javascript">
        function pageLoad() {
           $('div._Foo').bind("mouseover", function(e) {
               // Do something exciting
           });
        }
       

    </ContentTemplate>
</asp:UpdatePanel>

,因为pageLoad()是一个ASP.NET Ajax事件,每次在客户端加载页面时都会执行该事件。


我的答案是什么?

1
2
3
function pageLoad() {

  $(document).ready(function(){

等。

像个魔咒一样工作,许多其他的解决方案都失败了。


这对我很有用:

1
2
3
4
5
6
7
8
9
10
11
$(document).ready(function() {

    // Do something exciting

    var prm = Sys.WebForms.PageRequestManager.getInstance();

    prm.add_endRequest(function() {
        // re-bind your jQuery events here
    });

});

我将使用以下方法之一:

  • 将事件绑定封装到函数中,并在每次更新页面时运行它。您可以始终包含对特定元素的事件绑定,以便不将事件多次绑定到同一元素。

  • 使用LiveQuery插件,它基本上可以自动神奇地执行方法一。您的首选项可能会根据您希望对事件绑定拥有的控制量而有所不同。


  • 函数pageLoad()在这种情况下使用非常危险。您可以多次将事件连接起来。我还将远离.live(),因为它附加到document元素上,并且必须遍历整个页面(缓慢和糟糕)。

    到目前为止,我看到的最好的解决方案是在更新面板外的包装器上使用jquery.delegate()函数,并使用冒泡。除此之外,您可以始终使用Microsoft的Ajax库连接处理程序,该库是为使用UpdatePanels而设计的。


    当页面回发后$(document).ready(function (){...})不工作时,在asp.page中使用javascript函数pageload,如下所示:

    1
    2
    3
    4
    <script type="text/javascript" language="javascript">
    function pageLoad() {
    // Initialization code here, meant to run once.
    }


    我也遇到过类似的问题。重新附加事件是正确的操作,但需要在请求结束时完成。

    1
    2
    var prm = Sys.WebForms.PageRequestManager.getInstance();
    prm.add_endRequest(function() {...

    如果beginRequest导致您获取空引用JS异常,请记住这一点。

    干杯


    我遇到了一个类似的问题,发现最有效的方法是依靠事件冒泡和事件委托来处理它。事件委托的好处在于,一旦设置好,就不必在Ajax更新后重新绑定事件。

    我在代码中所做的是在更新面板的父元素上设置委托。更新时不会替换此父元素,因此事件绑定不受影响。

    在jquery中有许多优秀的文章和插件可以处理事件委托,这个特性很可能会被移植到1.3版本中。我引用的文章/插件是:

    http://www.danweb.net/2008/2/8/event-delegation-made-easy-in-jquery

    一旦你了解了它发生了什么,我想你会发现这是一个比记住每次更新后重新绑定事件更可靠的更优雅的解决方案。这还有一个额外的好处,即在卸载页面时,为您提供一个要解除绑定的事件。


    这是一个很好的插件,可用于更新面板:

    http://updatepanelplugin.codeplex.com/


    1
    2
    3
    4
    pageLoad = function () {
        $('#div').unbind();
        //jquery here
    }

    page load函数非常适合这种情况,因为它在初始页面加载和每个updatepanel异步回发时运行。我只需要添加unbind方法就可以使jquery在updatepanel回发上工作。

    http://encosia.com/document-ready-and-pageload-are-not-the-same/


    我的答案是基于上面的所有专家评论,但下面是以下代码,任何人都可以使用这些代码来确保每次回发和每次异步回发时仍将执行javascript代码。

    在我的例子中,我在一个页面中有一个用户控件。只需将下面的代码粘贴到您的用户控件中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <script type="text/javascript">
            var prm = Sys.WebForms.PageRequestManager.getInstance();
        prm.add_endRequest(EndRequestHandler);
        function EndRequestHandler(sender, args) {
            if (args.get_error() == undefined) {
                UPDATEPANELFUNCTION();
            }                  
        }

        function UPDATEPANELFUNCTION() {
            jQuery(document).ready(function ($) {
                /* Insert all your jQuery events and function calls */
            });
        }

        UPDATEPANELFUNCTION();

    每次加载之后,更新面板都会用其内置的scriptmanager脚本替换jquery。如果使用像这样的PageRequestManager实例方法会更好…

    1
    2
    3
    4
    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(onEndRequest)
        function onEndRequest(sender, args) {
           // your jquery code here
          });

    它会很好地工作…


    使用下面的脚本并相应地更改脚本的正文。

    1
    2
    3
    4
    5
            //Re-Create for on page postbacks
            var prm = Sys.WebForms.PageRequestManager.getInstance();
            prm.add_endRequest(function () {
               //your codes here!
            });

    针对布莱恩·麦凯的回答:

    我通过脚本管理器将JavaScript注入到我的页面中,而不是直接将其放入用户控件的HTML中。在我的例子中,我需要滚动到一个在updatepanel完成并返回后可见的表单。这将出现在代码隐藏文件中。在我的示例中,我已经在主内容页上创建了prm变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    private void ShowForm(bool pShowForm) {
        //other code here...
        if (pShowForm) {
            FocusOnControl(GetFocusOnFormScript(yourControl.ClientID), yourControl.ClientID);
        }
    }

    private void FocusOnControl(string pScript, string pControlId) {
        ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(),"focusControl_" + pControlId, pScript, true);
    }

    /// <summary>
    /// Scrolls to the form that is made visible
    /// </summary>
    /// <param name="pControlId">The ClientID of the control to focus on after the form is made visible</param>
    /// <returns></returns>
    private string GetFocusOnFormScript(string pControlId) {
        string script = @"
        function FocusOnForm() {
            var scrollToForm = $('#"
    + pControlId + @"').offset().top;
            $('html, body').animate({
                scrollTop: scrollToForm},
                'slow'
            );
            /* This removes the event from the PageRequestManager immediately after the desired functionality is completed so that multiple events are not added */
            prm.remove_endRequest(ScrollFocusToFormCaller);
        }
        prm.add_endRequest(ScrollFocusToFormCaller);
        function ScrollFocusToFormCaller(sender, args) {
            if (args.get_error() == undefined) {
                FocusOnForm();
            }
        }"
    ;
        return script;
    }

    1
    2
    3
    4
    5
    6
    Sys.Application.add_load(LoadHandler); //This load handler solved update panel did not bind control after partial postback
    function LoadHandler() {
            $(document).ready(function () {
            //rebind any events here for controls under update panel
            });
    }