jQuery $(document).ready和UpdatePanels?


475

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

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

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

不仅在首页加载时,而且在每次UpdatePanel触发部分页面更新时,建议在jQuery中进行接线的推荐方法是什么?我应该使用ASP.NET ajax生命周期来代替$(document).ready吗?


试试看,我认为它将解决您的问题codeproject.com/Articles/21962/…–
Baxterboom

Answers:


545

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
在进行说明时,请更加准确。我的意思是用法示例比几行分散的代码好得多。请参阅Brian MacKay的说明。这是完美的!
Trueseeker 2010年

3
@Dan(自jQuery 1.7 .delegate()起)已由.on()
Gabriele Petrioli

@ GabyakaG.Petrioli我意识到它已经被取代了,但是由于这个答案似乎解决了一个普遍的问题,我想最大化与尚未升级的旧版jQuery的兼容性。我先前的建议.live(...)是在1.7中正式弃用,在以后的版本中可能会删除。我故意选择了.delegate()它,因为它已经在jQuery中支持了一段时间,并且不太可能很快被删除。但是,.on()对于那些可以使用它的人,我也会对其答案进行升级。
丹·赫伯特

12
最好在$(document).ready中声明并连接prm var,因为可能尚未声明Sys(取决于脚本的位置)。
drake7707 2012年

1
@AhmedSamy不建议再使用jQuery.delegate()。已被jQuery.on()首选的API 所取代。delegate()只是针对特定用途的包装器,on()将来可能会弃用。我之前提到的评论delegate()是一年多以前写的,当时jQuery 1.7(引入了on()API)是新发布的。随着jQuery 1.9已经发布并且beta版本2.0准备发布,最好避免delegate()在任何新代码中使用。
丹·赫伯特

159
<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>

<EditItemTemplate>中的asp:GridView TextBox效果很好
Dan Randolph

这种解决方案的问题在于,尽管可行,但它杀死了UpdatePanel的异步回发,从而使UpdatePanel再次无用。(叹气)
MC9000,18年

63

在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>

所以...只是以为有人可能想知道这行得通。


2
我无法让它为我的一生工作。然后,我将其从头移动到页脚,然后开始工作。不是肯定的,但我认为需要在我正在使用的ScriptManager之后进行。
亚当·杨格斯

在我的情况下,我使用ScriptManager.RegisterClientScriptBlock添加脚本,该脚本在定义Sys之前添加了脚本,所以我最终使用了RegisterStartupScript(请参见此处的区别)
Firas Assaad 2012年

2
很酷的答案!在我的asp.net网络应用程序中,它像一种魅力一样工作。+为您服务
Pranesh Janarthanan

33

升级到jQuery 1.3并使用:

$(function() {

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

});

注意:现场直播适用于大多数事件,但并非全部。文档中有完整列表。


使用实时修复了更新面板的问题。不需要跳铁圈。
蒂姆·士嘉堡

那页面加载需要发生什么呢?例如斑马条纹表?$('TABLE TR:nth-​​child(odd)')。addClass('alt-row');
亚当·杨格斯

3
只是为了更新,自jQuery 1.7起,现在建议改用.on()
乔治

1
刚刚live()在IE7(jQuery 1.5.1 / VS2010项目)中使用该方法时发现严重故障。当使用live()一个UpdatePanel里面V3.5 ASP.NET一个普通AutoPostback<asp:DropDownList />原因,而不是预期的1浏览器发出额外的回传缺乏内容(中止)2个部分回发导致Page.IsPostBackfalse(杀死在我的束缚态控件)。我发现罪魁祸首是live()方法。我意识到第一个回发将被UpdatePanel按规范中止,但前提是队列中没有另一个回发。
timmi4sa

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事件,每次在客户端加载页面时都会执行该事件。


pageLoad在更新面板的每个ASync回发中重复事件。
Zo

17

我的答案?

function pageLoad() {

  $(document).ready(function(){

等等

像魅力一样运作,许多其他解决方案惨遭失败。


完美适合根据文本量在我的UserControl的UpdatePanel中的Listview中调整文本区域的大小。
资源

我努力使dom jquery函数在使用更新面板的回发中正常工作,该解决方案有效,并且我不必在2种情况下重复执行函数调用。这使jquery函数和侦听器可用。注意,我将所有脚本和jquery库都包括在页面底部FORM [end]标记之前。谢谢!!!
moto_geek

7

我将使用以下方法之一:

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

  2. 使用livequery插件,该插件基本上可以自动为您执行方法一。您的首选项可能会有所不同,具体取决于您希望对事件绑定进行控制的程度。


7

这为我工作:

$(document).ready(function() {

    // Do something exciting

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

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

});

6

在这种情况下使用pageLoad()函数非常危险。您可能使事件多次关联。我也会远离.live(),因为它附加到document元素上,并且必须遍历整个页面(缓慢而cr脚)。

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


6

$(document).ready(function (){...})页面回发后不起作用时,请按如下方式在Asp.page中使用JavaScript函数pageLoad:

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

:是的,检查isPartialLoad以及stackoverflow.com/questions/301473/...
史蒂夫格林

4

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

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

有很多不错的文章和插件可以处理jQuery中的事件委托,并且该功能很可能会集成到1.3版本中。我参考的文章/插件是:

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

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


4

FWIW,我在使用mootools时遇到了类似的问题。重新添加我的事件是正确的举动,但需要在请求结束时完成。

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

如果beginRequest使您获得空引用JS异常,则要记住一点。

干杯




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>

2

每次加载后,“更新面板”始终用其内置的Scriptmanager脚本替换您的Jquery。如果使用像这样的pageRequestManager的实例方法,效果会更好。

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

它将工作正常...


一篇旧文章,但这篇文章对我有帮助。我想补充一点:add_endRequest代码的位置必须在UpdatePanel内部,因为Sys.WebForms.PageRequestManager仅在那时可用。但是,实际功能不必位于该位置。因此,就我而言,我有一个script.js文件,该文件包含要绑定的代码,包含在一个函数中。在那个script.js文件中,我有一个document.ready调用,它将调用上述函数。然后,在我的UpdatePanel中,我具有add_endRequest代码,该代码也调用了上面的函数。
Kiran Ramaswamy

1

使用以下脚本,并相应地更改脚本的主体。

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

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

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
        });
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.