jQuery $(document).ready和UpdatePanels?

时间:2008-11-01 22:24:35

标签: javascript jquery asp.net javascript-events asp.net-ajax

我正在使用jQuery将一些鼠标悬停效果连接到UpdatePanel内的元素。事件绑定在$(document).ready中。例如:

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

当然,这在第一次加载页面时工作正常,但是当UpdatePanel执行部分页面更新时,它不会运行,并且鼠标悬停效果在UpdatePanel内部不再起作用。

建议的方法是什么是在jQuery中连接东西不仅在第一页加载,而且每次UpdatePanel激发部分页面更新?我应该使用ASP.NET ajax生命周期而不是$(document).ready吗?

19 个答案:

答案 0 :(得分:531)

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

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

$(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 :(得分:158)

<script type="text/javascript">

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

将要更新的区域。

<asp:UpdatePanel...
<ContentTemplate
     <script type="text/javascript">
                    Sys.Application.add_load(BindEvents);
     </script>
 *// Staff*
</ContentTemplate>
    </asp:UpdatePanel>

答案 2 :(得分:62)

在UpdatePanel内使用jQuery进行用户控制

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

我试图在用户控件中使用jQuery textarea限制器。这很棘手,因为用户控件在UpdatePanel内运行,并且它在回调时失去了绑定。

如果这只是一个页面,这里的答案将直接应用。但是,用户控件无法直接访问head标记,也没有像某些答案所假设的那样直接访问UpdatePanel。

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

<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();
    }); 

</script>

所以...只是觉得有人可能想知道这有效。

答案 3 :(得分:33)

升级到jQuery 1.3并使用:

$(function() {

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

});

注意:live适用于大多数事件,但不是全部。 the documentation中有一个完整的列表。

答案 4 :(得分:20)

您也可以尝试:

<asp:UpdatePanel runat="server" ID="myUpdatePanel">
    <ContentTemplate>

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

    </ContentTemplate>
</asp:UpdatePanel>

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

答案 5 :(得分:16)

我的回答?

function pageLoad() {

  $(document).ready(function(){

像魅力一样,许多其他解决方案都失败了。

答案 6 :(得分:7)

这对我有用:

$(document).ready(function() {

    // Do something exciting

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

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

});

答案 7 :(得分:7)

我会使用以下方法之一:

  1. 将事件绑定封装在函数中,并在每次更新页面时运行它。您始终可以包含与特定元素绑定的事件,以免多次将事件绑定到相同的元素。

  2. 使用livequery插件,它基本上可以自动执行方法一。您的偏好可能会有所不同,具体取决于您希望对事件绑定进行控制的数量。

答案 8 :(得分:6)

$(document).ready(function (){...})在页面回发后无效时,请在Asp.page中使用JavaScript函数pageLoad,如下所示:

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

答案 9 :(得分:6)

function pageLoad()在这种情况下使用非常危险。您可以让事件多次连线。我也会远离.live(),因为它附加到文档元素并且必须遍历整个页面(缓慢而蹩脚)。

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

答案 10 :(得分:4)

这是一个用于更新面板的绝佳插件:

http://updatepanelplugin.codeplex.com/

答案 11 :(得分:4)

FWIW,我遇到过与mootools类似的问题。重新附加我的事件是正确的举动,但需要在请求结束时完成.eg

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

如果beginRequest导致您获得空引用JS异常,请记住一些事项。

干杯

答案 12 :(得分:4)

我遇到了类似的问题,发现最好的方法是依靠Event Bubbling和事件委托来处理它。关于事件委托的好处是,一旦设置完成,您就不必在AJAX更新后重新绑定事件。

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

在jQuery中有许多好的文章和插件来处理事件委托,这个功能可能会被纳入1.3版本。我用来参考的文章/插件是:

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

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

答案 13 :(得分:3)

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

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

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

答案 14 :(得分:2)

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

就我而言,我在页面中有一个用户控件。只需将以下代码粘贴到您的用户控件中即可。

<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(); 

</script>

答案 15 :(得分:2)

每次加载后,

更新面板始终会将其Jquery替换为内置的Scriptmanager脚本。如果你使用像这样的pageRequestManager的实例方法,它会更好......

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

它会正常工作......

答案 16 :(得分:0)

回应Brian MacKay的回答:

我通过ScriptManager将JavaScript注入我的页面,而不是直接将其放入UserControl的HTML中。在我的情况下,我需要滚动到一个在UpdatePanel完成并返回后可见的表单。这包含在代码隐藏文件中。在我的示例中,我已经在主要内容页面上创建了 prm 变量。

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;
}

答案 17 :(得分:0)

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
        });
}

答案 18 :(得分:0)

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

       <script>
        //Re-Create for on page postbacks
        var prm = Sys.WebForms.PageRequestManager.getInstance();
        prm.add_endRequest(function () {
           //your codes here!
        });
    </script>