【问题标题】:Loading usercontrols on demand under jquery tabs在 jquery 选项卡下按需加载用户控件
【发布时间】:2011-12-31 02:13:10
【问题描述】:

我在一个用户控件上有几个 jquery 选项卡,它们在每个选项卡下加载一个单独的用户控件。每个用户控件都是唯一的。现在一切正常,但整体页面响应太慢。为了提高性能,我尝试在这些选项卡下按需加载一些用户控件(即单击选项卡)。可能没有回邮... ajaxish。 谁能指导我? 我也尝试遵循this 教程和this 之一,但没有任何成功。我附上了父用户控件的代码。

<ul id="tabs">
<li class="active">Rewards</li>
<li id="liCoupons">Coupons</li>
<li id="liLibrary">Library</li>
<li id="liProducts">Favorite</li>
<li id="liPreferences">Preferences</li></ul><ul id="tabPanes" class="rewardsTabs">
<li>
    <div class="wrapper active">
        <uc:Rewards ID="wellness" runat="server" />

    </div>
</li>
<li id="liCoupons">
    <div class="wrapper">
        <uc:Coupon runat="server" />
    </div>
</li><li id="liLibrary">
    <div class="wrapper">
        <uc:Library runat="server" />
    </div>
</li><li id="liProducts">
    <div class="wrapper">
        <uc:Products runat="server" />
    </div>
</li>
<li>
    <div class="wrapper">
        <div class="preferences">
            <uc:Preferences runat="server"/>
        </div>

    </div>
</li>

【问题讨论】:

  • 基本上我希望在单击选项卡时按需加载用户控件。没有回发或在更新面板中,这样用户就看不到整个页面的加载。最好带有加载微调器。
  • 您的UserControls 中有什么?您是否正在检查权限级别或某种用户组以生成不同的菜单项?
  • 所有用户的菜单项都相同。他们没有对权限或任何东西进行任何检查。除了其中的数据(例如:帐户信息0
  • 你能从其中一个中发布一些代码吗?我试图弄清楚是否有办法处理这个问题,可以让你删除UserControls 并做一些稍微不同的事情,比如编写一个构建菜单的整个 ASP.NET 页面,然后通过加载该页面阿贾克斯。我建议使用 UserControls 进行类似的操作,但我从未使用过 AJAX。
  • 我现在手头没有代码,但它们只是普通的 UC。有些有带有回发操作的按钮,有些有表单字段和带有 ajax 发布的按钮。他们非常独立。如果你坚持要代码,我会在我回家时(美国东部标准时间下午 6 点)把它放在这里。

标签: c# asp.net jquery user-controls asp.net-ajax


【解决方案1】:

您的用户控件是否依赖回发和视图状态才能正常工作?使用 AJAX 获取要在选项卡中显示的用户控件 HTML 将相对容易,但随后对该控件的回发会将整个数据发送到实际页面(可能未加载用户控件)。所以基本轮廓是

  1. 使用隐藏变量或视图状态跟踪活动选项卡。
  2. 在早期页面循环中基于活动选项卡加载用户控件。最好的选择是 init 阶段(并非此处不提供视图状态,因此您必须将活动选项卡存储在隐藏变量中并通过 Request.Forms 集合访问它)。
  3. 给每个用户控件一个 ID,它应该在不同的选项卡之间有所不同。 ID 对于加载视图状态非常重要。
  4. 如果在选项卡切换时出现损坏的视图状态错误,则需要先加载前一个选项卡的用户控件,然后在页面后期(例如加载/预渲染)卸载它并为活动选项卡加载新的用户控件.
  5. 您可以在每个选项卡窗格中使用占位符或面板控件将用户控件加载到正确的位置。
  6. 不用说,在更改 jquery 选项卡时,您需要使用回发脚本提交表单。每次回发后,您需要有一个脚本来重新初始化选项卡并选择活动选项卡。
  7. 为了获得更好的用户体验,请将整个内容放入 UpdatePanel。

【讨论】:

  • 我认为他们的工作不需要视图状态。你有任何示例代码或指向某个地方吗?
【解决方案2】:

如果你用 jquery 稍微调整一下,这应该可以工作:
http://blogs.msdn.com/b/sburke/archive/2007/06/13/how-to-make-tab-control-panels-load-on-demand.aspx

或者您只使用 asp.net 选项卡。

【讨论】:

    【解决方案3】:

    也许使用指向下面定义的服务的锚点。例如,

    <li><a href="...webservices/ControlServce.svc/Content?cType=Rewards" class="wrapper active"></a></li> 
    
    /// <summary>
    /// Service used by ajax for loading social media content
    /// </summary>
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ControlService
    {
        /// <summary>
        /// Streams html content
        /// </summary>
        /// <param name="type">type of control</param>
        /// <returns>html stream of content</returns>
        [OperationContract]
        [WebGet(UriTemplate = "Content?cType={cType}")]
        public Stream GetContent(string cType)
        {
            var tw = new StringWriter();
            var writer = new Html32TextWriter(tw);
    
            var page = new Page();
            var control = page.LoadControl(cType);
    
            control.RenderControl(writer);
    
            writer.Close();
    
            var stream = new MemoryStream(Encoding.UTF8.GetBytes(tw.ToString()));
    
            WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
            WebOperationContext.Current.OutgoingResponse.Headers.Add("Cache-Control", "no-cache");
            return stream;
        }
    }
    

    【讨论】:

    • 你能展示一些示例代码吗? JS和代码通过ashx处理程序吐出html?
    【解决方案4】:

    你提到的second link 应该可以工作。您无需在标记中定义任何用户控件。

    <ul id="tabs">
        <li class="active">Rewards</li>
        <li id="liCoupons">Coupons</li>
        <li id="liLibrary">Library</li>
        <li id="liProducts">Favorite</li>
        <li id="liPreferences">Preferences</li>
    </ul>
    <div id="results" class="wrapper"></div>
    

    每次标签点击都会进行一次 ajax 调用

    $.ajax({
           type: "POST",
           url: "Default.aspx/WebMetodToCall", 
           data: data, // I wouldn't prefer passing webmethod name here
           contentType: "application/json; charset=utf-8",
           dataType: "json",
           success: function (msg) {
               $('#result').html(msg.d);
           },
           failure: function (msg) 
               //error
           }
       });
    

    到网络方法。

    [WebMethod]
       public static string Rewards()
       {
           return RenderControl("~/controls/rewardsControl.ascx");
       }
    
    [WebMethod]
       public static string Coupons()
       {
           return RenderControl("~/controls/couponsControl.ascx");
       }    
    ...
    

    每个方法将只呈现请求的控件。同样在您的方法中,您可以根据需要保留或提取视图状态。渲染后,webmethod 应该将要注入到占位符中的 html 字符串传回。

    如果您尝试过此操作并成功地一次渲染一个控件,但仍然看到速度缓慢,那么您在获取数据时遇到了一些后端问题。如果您的控件数据量很大,我建议您进行一些服务器端缓存。

    希望这会有所帮助。

    【讨论】:

    • 这很好......我们如何进行标签点击?像这样?
  • 我认为这有点臭(将一个 AJAX 方法绑定到几个 WebMethods),但总的来说是这里发布的最佳解决方案(特别是考虑到问题中的特殊情况)。
  • @xoail 您可以使用 jquery 将点击事件绑定到您想要的任何 DOM 元素。看看api.jquery.com/click
  • @jwiscarson 不知道为什么臭,符合单一责任原则。另外,我会将加载控件的处理移至不同的类,以便保持 webmethod 类更轻。
  • @zero7 我可以使用 .ashx 处理程序而不是 WebMethod 吗?如果是这样,方法是否相同?我问的原因是,我已经有一个 Service.ashx 文件,我可以针对这种情况进行扩展。
  • 【解决方案5】:

    您应该使用 jquery 和 webmethod 获取第二个链接。这样一来,您实际上可以按需填充选项卡,而不会使您的页面变得沉重。

    【讨论】:

      【解决方案6】:

      您需要进行 Ajax 调用才能进行此操作。 现在您可以选择调用 AJAX:

      1 - 通过 SOAP Web 服务调用(每个 Web 方法都需要 ASP AjaxScriptManager 引用)。

      2- 通过 WCF 服务调用作为上一个答案。

      3 - 通过 Rest 服务调用。

      4- 通过 Jquery ajax 方法调用,但请求必须转到外部页面,如“Actions.aspx”,因此当您调用您的方法时,HTTPRequest 将进入 Actions 页面,然后它将在其响应中包含返回的数据。 $.Ajax(url,data,action,successMethod); // this is the fastest way I tried them all.

      这是你应该做的: 1- 在更改选项卡事件上,使用上述选项中适当的 Ajax 调用方法调用您的方法。

      2- 从 success 方法中使用返回的数据,但最好对 DataTime 对象使用 eval(data)。

      这里有一些例子解释了如何进行这个调用:

      var helper = {
      callAjax: function(sentData, successFun) {
              jQuery.ajax({
                  url: "/Actions.aspx",
                  type: "Get",
                  data: sentData,
                  cache: true,
                  dataType: "json",
                  success: successFun
              });
          }
      };
      
      helper.callAjax('request=getCities&countryID=' + countryID, function (args) {
         var result = eval(args); // this object will contain the returned data
      var htmlData = '';
          for (var i=0;i<result.length;i++){
          // write your HTML code by jQuery like this
          htmlData  += '<div>' +  result[i].title + '</div>';
      }
      $('#tab3').html(htmlData);
      });
      

      现在在 Actions.ASPX 代码中使用以下代码:

       protected void Page_Load(object sender, EventArgs e)
          {
              object _return = new
              {
                  error = "",
                  status = true
              };
              JavaScriptSerializer _serializer = new JavaScriptSerializer();
              if (!Page.IsPostBack)
              {
                  string str = Request.QueryString["request"].ToString();
                  switch (str.ToLower())
                  {
      case "getcities":
                          int countryID = Convert.ToInt32(Request.QueryString["countryID"].ToString());
                          _return = JQueryJson.Core.City.getAllCitiesByCountry(countryID).Select(_city => new
                          {
                              id = _city.ID,
                              title = _city.Name
                          });
                          _serializer = new JavaScriptSerializer();
                          Response.ClearContent();
                          Response.ClearHeaders();
                          Response.ContentType = "text/json";
                          Response.Write(_serializer.Serialize(_return));
                          break;
      }
      // etc........
      }
      

      【讨论】:

      • 谢谢...不幸的是,在您的回答中,我看到您返回的是 json 而不是 usercontrol 它自己。使用 $.ajax,我可以使用 .ashx 处理程序并返回 usercontrol 标记吗?
      【解决方案7】:

      在我看来,解决您的问题的最快方法(但不一定是最好的长期解决方案)是将您的所有UserControls 包装在一个 .aspx 页面中。在这种情况下,您只需将父 UserControl 标记移动到新的 .aspx 页面,并通过 AJAX 调用它。

      假设您将此页面称为 Menu.aspx,并进一步假设您不需要将任何数据传递到此页面(也就是说,它可以在内部跟踪自己的所有数据),您的 jQuery AJAX 调用将如下所示:

      function GetMenu ($placeholder) {
          $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", dataType: "json",
              url: "Menu.aspx",
              done: function (result) {
                  $placeholder.html(result.d);
              },
              fail: function () {
                  $placeholder.html("Error loading menu.");
              }
          });
      }
      

      一些注意事项:

      1. donefail 将替换 jQuery 1.8 中的 successerror,因此您使用的任何 jQuery AJAX 都应该为这种转换做好计划。
      2. 我将它封装在一个函数中主要是因为我更喜欢将 AJAX 调用放在 JS 类和函数中,然后引用这些对象。使用菜单,您不太可能有多个不同的页面通过 AJAX 加载相同的数据(因为这将在某种母版页上,我猜),但让自己养成这样做的习惯总是好的东西。
      3. 根据您对紧密耦合的 HTML/JavaScript 的感受,您可以将上面的 $placeholder 替换为回调函数。从菜单所在的页面调用它看起来像:

        $(document).ready(function () {
            GetMenu(MenuCallback);
        });
        
        function MenuCallback(menuHtml) {
            $("#menu").html(menuHtml); // I'm assuming the ID of your ul/span/div tag here.
        }
        
      4. 有些人(包括我自己)使用 $ 前缀来区分 JavaScript 和 jQuery 变量。所以这里,$placeholder 是一个 jQuery 变量。

      5. 您也许可以将这个$.ajax 调用重写为type: "GET",这样效率会更高一些,但我不确定UserControls 是否会在这方面造成问题。通常,如果我通过 AJAX 加载整个 .aspx 页面,我会使用 GET 而不是 POST。您无需进行太多更改即可试用:只需切换 type 属性并将 result.d 更改为 result

      【讨论】:

        【解决方案8】:

        我认为最好的解决方案是实现客户端回调

        http://msdn.microsoft.com/en-us/library/ms178210.aspx

        当用户单击某个选项卡时,onclick 事件以选项卡名称作为参数调用 js func,而不是该选项卡调用具有相同参数的服务器代码。

        比在代码中加载所需的控件取决于单击哪个选项卡。 现在您需要将控件呈现为 html 并将其发送回 js 函数。 现在你在js函数中有了控件,找到你要插入代码的地方插入它。

        理论上应该可行,而且并不复杂:))

        【讨论】:

          【解决方案9】:

          对这个问题的回答(不是我的)可能对你有用:

          Asynchronous loading of user controls in a page

          它指出存在问题,需要用户控件上的表单来回发,但是应该可以使用带有 ajax 发布的独立表单。您必须考虑在页面上发布表单时会发生什么,但不应该是不可克服的。不应该是你不能让它成为你提到的 ashx 处理程序的任何原因。

          【讨论】:

            猜你喜欢
            相关资源
            最近更新 更多
            热门标签