仅当页面向下滚动MVC 4 Jquery Mobile时才加载数据

时间:2013-11-18 07:02:40

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

在我看来,我正在填充从一个有超过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>

    }}

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

2 个答案:

答案 0 :(得分:1)

RustyLazyLoad由六个主要组件组成:

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

首先,我们将快速浏览rustylazyload.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 - 数据容器对象的标识(<ul id="thisId"></ul>
_ajaxLoadContainerId - &#34;加载&#34;的ID消息容器对象(<div id="thisId">Loading..</div>
_ajaxActionUrl - 将使用$ .ajax()来调用的动作Url _parameters - 一个JSON对象,它有2个必填字段:limit(按需加载的项数)和fromRowNumber(标记第N个加载项以避免重复输入)。

我们不会逐行讨论这些代码,而只是突出重要部分:

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

load()使用jQuery AJAX调用_ajaxActionUrl并传递_parameters变量中的所有指定参数 - ASP.NET MVC足够智能,可以使用Controller操作参数映射这些参数

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

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

接下来是rustylazyload.css,应该很直接:

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

现在,View Model 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; }
}
}

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

<强> _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,我们需要做的就是在RustyLazyLoadViewModel.cs中添加AjaxLoadContainerId属性并将其传递给变量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个用户条目包含以下字段: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中,我们需要为我们的Index页面创建默认的[HttpGet] Controller操作方法Index(),并为[HttpPost] Controller操作方法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()的视图)中,我们将有这样的内容:

@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。我转发它仅用于信息共享。您可以找到工作模型

    1st image
    2nd image
    3rd image

  • 答案 1 :(得分:0)

    我还没有尝试过,但很快就会寻找类似的解决方案:该术语称为“延迟加载”

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