【问题标题】:Load data only when page is scrolled down MVC 4 Jquery Mobile仅在页面向下滚动时加载数据 MVC 4 Jquery Mobile
【发布时间】:2013-12-01 06:11:42
【问题描述】:

在我看来,我正在填充从具有 1000 多条记录的表中获取的内容。我必须以仅在向下滚动而不是立即将记录填充到较少记录的方式填充内容。我用它来开发移动应用程序。我已经尝试了各种在线资源,但在滚动的范围内没有效果。如果您仍然不清楚我的问题,那么你们中的大多数人可能都使用过 facebook。那里的帖子不会一次全部加载。只有在滚动时才会加载它们。我必须实现相同的功能。任何对实时代码的引用将不胜感激。提前致谢。

这是我获取记录的代码

@foreach (System.Data.DataRow row in Model.dtSearch.Rows)
{
if (Model.dtSearch.Rows.Count > 0)
    {
    <input type ="hidden" value="@row["ProductId"]" />
    <input type ="hidden" value="@row["ProductPriceId"]" />

    <div class="divSearchResult" id="divSearch">
    <table>
    <tbody>
    <tr><td rowspan="2" style="width:10%"> @Html.Raw(row["ThumbnailFilename"])</td>
    <td colspan="3"><div class="divSearchHeader"> @row["ProductName"] <br /></div></td></tr>
    <tr><td colspan="4"><div class="divSearchShowHide" ><a class="classShow" id="show" href="#" style="text-decoration:none">Show</a></div>
    <div style="display:none;" class="divSearchContent" id=divresult_@ProductDescription > @Html.Raw(row["ProductDescription"])</div></td></tr>
    </tbody>
    </table>
    <hr />
</div>

    }}

显示代码没有意义,但这是我必须实现功能的地方

【问题讨论】:

标签: c# asp.net ajax asp.net-mvc-4 jquery-mobile


【解决方案1】:

我还没有尝试过,但很快就会寻找类似的灵魂:这个术语被称为“延迟加载”

http://dcarrith.github.io/jquery.mobile.lazyloader/

【讨论】:

    【解决方案2】:

    RustyLazyLoad 由六个主要组件组成:

    1.rustylazyload.js
    2.rustylazyload.css
    3.RustyLazyLoadViewModel.cs
    4._RustyLazyLoad.cshtml
    5.你的Controller延迟加载动作方法和对应的ViewModel
    6.你的PartialView模板

    首先,我们将快速运行 rustyllazyload.js:

    function LazyLoad(uniqueId) {
    
    var _uniqueId = uniqueId;
    
    var _containerId = "";
    var _ajaxLoadContainerId = "";
    var _ajaxActionUrl = "";
    var _parameters = {};
    
    this.init = function(option) {
    
        _containerId = option.containerId;
        _ajaxLoadContainerId = option.ajaxLoadContainerId;
        _ajaxActionUrl = option.ajaxActionUrl;
        _parameters = option.parameters;
    
        // Enable scroll event handler
        bindScrollHandler();
    
        // Load initial items
        load();
    };
    
    var bindScrollHandler = function() {
        $(window).scroll(function() {
            if ($(window).scrollTop() + $(window).height() > $(document).height() - 200) {
                load();
            }
        });
    };
    
    var unbindScrollHandler = function() {
        $(window).unbind("scroll");
    };
    
    var load = function() {
        $.ajax({
            type: "POST",
            url: _ajaxActionUrl,
            data: _parameters,
            beforeSend: load_beforeSend,
            success: load_success,
            error: load_error
        });
    };
    
    var load_beforeSend = function() {
        // Disable scroll event handler
        unbindScrollHandler();
    
        // Show loading message
        $(_ajaxLoadContainerId).toggleClass("lazyload-hidden").html("Loading..");
    };
    var load_success = function(result) {
    
        // Delay a bit before displaying the result and re-enabling scroll event handler
        setTimeout(function() {
            // Display result with fade in effect
            if (result != null && result != "") {
                $(_containerId).append(result, { duration: 500 });
                // Add ui-first-child to the first child
                $(_containerId).find(">:first-child").removeClass("ui-first-child");
                $(_containerId).find(">:first-child").addClass("ui-first-child");
                // Remove ui-last-child from the old last child
                $(_containerId).find(">:nth-child(" + _parameters.fromRowNumber + ")").removeClass("ui-last-child");
                // Add ui-last-child to the new last child
                $(_containerId).find(">:last-child").addClass("ui-last-child");
    
                // Update fromRowNumber
                _parameters.fromRowNumber = $(_containerId).children().length;
            }
    
            if (_parameters.fromRowNumber == 0) {
                // Use loading container to display 'no item' message
                $(_ajaxLoadContainerId).html("There is no data to display");
            } else {
                // Remove loading message
                $(_ajaxLoadContainerId).toggleClass("lazyload-hidden").html("");
            }
    
            // Re-enable scroll handler
            bindScrollHandler();
        }, 500);
    
    };
    var load_error = function(result) {
        var message = result.responseText.substring(1, result.responseText.length - 2);
        $(_ajaxLoadContainerId).html("Error: " + message);
    };
    } 
    

    调用 init() 时需要指定 4 个必填字段:

    _containerId - 数据容器对象的 ID (&lt;ul id="thisId"&gt;&lt;/ul&gt;)
    _ajaxLoadContainerId - “正在加载”消息容器对象的 ID (&lt;div id="thisId"&gt;Loading..&lt;/div&gt;)
    _ajaxActionUrl - 将使用 $.ajax() 调用的操作 Url
    _parameters - 一个 JSON 对象,它有 2 个必填字段:limit(按需加载的项目数)和 fromRowNumber(标记第 N 个加载的项目以避免重复输入)。

    我们不会逐行讨论上面的代码,而是只突出显示重要的部分:

    init() 函数做了三件事:映射参数,将滚动事件处理程序绑定到窗口,并调用 load() 以显示第一批
    bindScrollHandler() 非常简单——它只是确保在窗口几乎到达底部时调用 load()

    load() 使用 jQuery AJAX 调用 _ajaxActionUrl 并在 _parameters 变量中传递所有指定的参数 - ASP.NET MVC 足够聪明,可以将这些参数映射到控制器操作参数

    当 Controller 动作执行时,load_beforeSend() 暂时禁用窗口滚动事件处理程序,这样我们就不会用 AJAX 请求重载服务器,同时显示 Id 存储在 _ajaxLoadContainerId 中的加载消息 HTML 对象 成功时,load_success() 应该将结果绑定到 _containerId HTML 对象,使用加载的项目数更新 _parameters.fromRowNumber(记住 fromRowNumber 是 _parameters 的必需项之一),并重新启用窗口滚动事件处理程序 任何错误都会在 load_error() 中处理,会显示在 _ajaxLoadContainerId HTML 对象中

    如果您使用的是默认的 ASP.NET MVC4 移动应用程序模板,则根本不需要修改此文件

    接下来是 rustyllazyload.css,应该很简单:

    .lazyload-loading-container {
    margin: 0;
    padding: 15px;
    text-align: center;
    }
    .lazyload-hidden {
    display: none;
     }
    

    现在,查看模型 RustyLazyLoadViewModel.cs:

      using System.Collections.Generic;
    
      namespace RustyLazyLoadTester.Mobile.Models
      {
    public class RustyLazyLoadViewModel
    {
        public RustyLazyLoadViewModel()
        {
            Parameters = new Dictionary<string, object>();
        }
        public RustyLazyLoadViewModel(int limit, int fromRowNumber, string containerId,
            string ajaxActionUrl, IDictionary<string, object> parameters = null)
        {
            Limit = limit;
            FromRowNumber = fromRowNumber;
            ContainerId = containerId;
            AjaxActionUrl = ajaxActionUrl;
            if (parameters != null)
                Parameters = parameters;
        }
    
        public int Limit { get; set; }
        public int FromRowNumber { get; set; }
        public string ContainerId { get; set; }
        public string AjaxActionUrl { get; set; }
        public IDictionary<string, object> Parameters { get; set; }
    }
    }
    

    如您所见,此视图模型捕获与 rustyllazyload.js 的 .init() 函数几乎相同的参数,除了没有 _ajaxLoadContainerId。为什么?让我们看看视图文件。

    _RustyLazyLoad.cshtml:

     @using System.Text
     @model RustyLazyLoadTester.Mobile.Models.RustyLazyLoadViewModel
     @{
    var containerId = Model.ContainerId;
    var ajaxLoadContainerId = string.Format("{0}Load", containerId);
    
    // Convert parameters to JSON
    var sbParameters = new StringBuilder();
    if (Model.Parameters != null && Model.Parameters.Any())
    {
        foreach (var parameter in Model.Parameters)
        {
            sbParameters.AppendFormat("\"{0}\": \"{1}\", ", parameter.Key, parameter.Value);
        }
    }
    var parameters = sbParameters.ToString();
    // Remove trailing ', ' from parameters
    if (!string.IsNullOrWhiteSpace(parameters))
    {
        parameters = parameters.Substring(0, parameters.Length - 2);
    }
    }
    <ul id="@containerId" data-role="listview" 
             data-inset="true"></ul>
    <div id="@ajaxLoadContainerId"
     class="lazyload-loading-container lazyload-hidden
            ui-listview ui-listview-inset
            ui-corner-all ui-shadow ui-li-static
            ui-btn-down-b ui-first-child ui-last-child"></div>
    <script type="text/javascript">
    $(document).ready(function () {
        var limit = @Model.Limit;
        var fromRowNumber = @Model.FromRowNumber;
        var containerId = '@string.Format("#{0}", containerId)';
        var ajaxLoadContainerId = '@string.Format("#{0}", ajaxLoadContainerId)';
        var ajaxActionUrl = '@Model.AjaxActionUrl';
        var parameters = { limit: limit, fromRowNumber: fromRowNumber, @Html.Raw(parameters) };
    
        var lazyLoad = new LazyLoad(containerId);
        lazyLoad.init({
            containerId: containerId,
            ajaxLoadContainerId: ajaxLoadContainerId,
            ajaxActionUrl: ajaxActionUrl,
            parameters: parameters
        });
    });
    </script>
    

    为简单起见,_ajaxLoadContainerId 实际上只是带有后缀的 _containerId,但实际上它可以是任何东西。如果我们觉得需要手动指定您的 AJAX 加载消息容器 Id,我们需要做的就是将 AjaxLoadContainerId 作为属性添加到 RustyLazyLoadViewModel.cs 并将其传递给变量 ajaxLoadContainerId(本页第 5 行)。

    延迟加载项容器是这样的:

     <ul id="@containerId" data-role="listview" data-inset="true"></ul> 
    

    而延迟加载加载消息容器是这样的:

     <div id="@ajaxLoadContainerId" ...></div>  
    

    然后使用 Razor 引擎,我们将参数转换为 JSON 并将其传递给延迟加载控件。

    var parameters = { limit: limit, fromRowNumber: fromRowNumber, @Html.Raw(parameters) };
    
    var lazyLoad = new LazyLoad(containerId);
    lazyLoad.init({
    containerId: containerId,
    ajaxLoadContainerId: ajaxLoadContainerId,
    ajaxActionUrl: ajaxActionUrl,
    parameters: parameters
    }); 
    

    最后,第五和第六部分最好通过一个例子来解释。

    假设数据库中有 15 个 User 条目,其中包含以下字段:Id、FirstName、LastName、Status 并映射到下面的模型。并且我们希望使用延迟加载控件以渐进方式在主页上显示条目。

     using System.ComponentModel;
    
     namespace RustyLazyLoadTester.Mobile.Services.Models
     {
    public class User
    {
        public User() { }
        public User(long id, string firstName, string lastName, UserStatus status)
            : this()
        {
            Id = id;
            FirstName = firstName;
            LastName = lastName;
            Status = status;
        }
    
        public long Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public UserStatus Status { get; set; }
    }
    
    public enum UserStatus
    {
        [Description("All")]
        All = 0,
        [Description("Inactive")]
        Inactive = 1,
        [Description("Active")]
        Active = 2,
        [Description("Deactivated")]
        Deactivated = 3
    }
    }
    

    我们需要做的第一件事是创建服务方法:

    using System.Collections.Generic;
    using System.Linq;
    using RustyLazyLoadTester.Mobile.Services.Models;
    
    namespace RustyLazyLoadTester.Mobile.Services
    {
    public interface IQueryService
    {
        IEnumerable<User> GetAllUsers(UserStatus status = UserStatus.All,
                                      int limit = 0, int fromRowNumber = 0);
    }
    
    class QueryService : IQueryService
    {
        public IEnumerable<User> GetAllUsers(UserStatus status, int limit, int fromRowNumber)
        {
            // Assume we have 15 users
            var users = new List<User>();
            for (var i = 0; i < 15; i++)
            {
                var userFirstName = string.Format("firstName_{0}", i);
                var userLastName = string.Format("lastName_{0}", i);
                var userStatus = i % 2 == 0 ? UserStatus.Active : UserStatus.Inactive;
                users.Add(new User(i, userFirstName, userLastName, userStatus));
            }
    
            if (limit <= 0)
            {
                users = users.Where(x => x.Status == status)
                            .Skip(fromRowNumber)
                            .ToList();
            }
            else
            {
                users = users.Where(x => x.Status == status)
                            .Skip(fromRowNumber)
                            .Take(limit)
                            .ToList();
            }
            return users;
        }
    }
    }
    

    在我们的 HomeController 中,我们需要为索引页面创建默认的 [HttpGet] 控制器操作方法 Index() 和 [HttpPost] 控制器操作方法 GetNextUsers() 以服务于惰性加载器:

    using System;
    using System.Linq;
    using System.Net;
    using System.Web.Mvc;
    using RustyLazyLoadTester.Mobile.Services;
    using RustyLazyLoadTester.Mobile.Services.Models;
    
    namespace RustyLazyLoadTester.Mobile.Controllers
    {
    public class HomeController : Controller
    {
        private readonly IQueryService _query;
    
        public HomeController()
        {
            _query = new QueryService();
        }
    
        [HttpGet]
        public ActionResult Index()
        {
            return View();
        }
    
        [HttpPost]
        public ActionResult GetNextUsers(UserStatus status, int limit, int fromRowNumber)
        {
            try
            {
                var users = _query.GetAllUsers(status, limit, fromRowNumber);
    
                if (!users.Any())
                    return Json(string.Empty);
    
                return PartialView("_UserList", users);
            }
            catch (Exception ex)
            {
                Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                return Json(ex.Message);
            }
        }
    }
    }
    

    在Index.cshtml(对应于[HttpGet]控制器动作方法Index()的View)中我们会有这样的:

    @using RustyLazyLoadTester
    @using RustyLazyLoadTester.Mobile.Models
    @using RustyLazyLoadTester.Mobile.Services.Models
    @{
    ViewBag.PageTitle = "Home";
    ViewBag.Title = string.Format("RustyLazyLoadTester - {0}", ViewBag.PageTitle);
    
    var parameters = new Dictionary<string, object>();
    parameters.Add("status", UserStatus.All);
    }
    @Scripts.Render("~/bundles/lazyload") @* points to /Scripts/rustylazyload.js *@
    
    @Html.Partial("_RustyLazyLoad", new RustyLazyLoadViewModel(
    5, 0, "ulUsers", Url.Action("GetNextUsers", "Home"), parameters))
    

    那里的两条粗体线将激活延迟加载控件并按需触发 GetNextUsers()。

    如果我们仔细观察第二条粗体线:

    @Html.Partial("_RustyLazyLoad", new RustyLazyLoadViewModel(
    5, 0, "ulUsers", Url.Action("GetNextUsers", "Home"), parameters)) 
    

    值 5 是限制。这决定了每次加载时要检索的项目数。值 0 是 fromRowNumber。这表示结果中需要忽略的第 N 项。随着我们加载更多数据,这个数字会根据加载的项目而增加,所以我们不必担心重复(除非我们的代码涉及一些复杂的排序,这使得列表中间可以有一个新项目) .

    当调用 GetNextUsers() 方法时,它只是在下面呈现 PartialView _UserList.cshtml:

    @using Humanizer
    @using RustyLazyLoadTester.Mobile.Services.Models
    @model IEnumerable<User>
    
    @foreach (var user in Model)
    { 
    <li class="ui-li ui-li-static ui-btn-up-b">
        <div>@string.Format("First name: {0}", user.FirstName)</div>
        <div>@string.Format("Last name: {0}", user.LastName)</div>
        <div>@string.Format("Status: {0}", user.Status.Humanize())</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
        <div>---</div>
    </li>
    }
    

    注意,内容被包裹在一个

  • 。这样做的原因是因为父容器(_containerId HTML 对象)是一个 .但是我们总是可以很容易地改变这个实现,只要我们保持如下的层次结构:
    <parentContainer>
      <childContainer>
         [Content]
      </childContainer>
    </parentContainer> 
    

    这是因为 RustyLazyLoad 控件使用父容器的子容器数量来更新 _fromRowNumber 属性,从而确保下次加载时没有重复条目。

    上面的代码不是我写的。但是我已经成功地在我的项目中使用了。参考来自link,您可以在其中获得完整描述。所有归功于 Teddy Segoro 。我转发它只是为了分享信息。您可以找到工作模型



  • 【讨论】:

    • 非常感谢您的努力。我会试试这个。也将把它作为答案。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 2015-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多