Подгрузка с прокруткой списка в ASP.NET MVC и Web API

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 1.11.2015

На многих сайтах можно встретить такую функциональность как inifinite scrolling или бесконечный кроллинг, который предполагает постепенную подгрузку контента по мере прокрутки пользователем браузера. Стандартный пример: прокрутка тем в вконтакте, когда происходит плавная подгрузка постов. Попробуем реализовать подобную возможность.

Определим модель данных, которые будут подгружаться:

public class Phone
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Company { get; set; }
}

Контроллер будет выглядеть следующим образом:

public class HomeController : Controller
{
    List<Phone> phones;
    const int pageSize = 8;
    public HomeController()
    {
        phones = new List<Phone>
        {
            new Phone {Id=1, Name="Samsung Galaxy III", Company="Samsung"},
            new Phone {Id=2, Name="Samsung Galaxy IV", Company="Samsung"},
            new Phone {Id=3, Name="Samsung Galaxy Ace II", Company="Samsung"},
            new Phone {Id=4, Name="iPhone 5s", Company="Apple"},
            //.................................
            new Phone {Id=25, Name="LG G3", Company="LG"}
        };
    }
    public ActionResult Index(int? id)
    {
        int page = id ?? 0;
        if (Request.IsAjaxRequest())
        {
            return PartialView("_Items", GetItemsPage(page));
        }
        return View(GetItemsPage(page));
    }

    private List<Phone> GetItemsPage(int page=1)
    {
        var itemsToSkip = page * pageSize;

        return phones.OrderBy(t=>t.Id).Skip(itemsToSkip).
            Take(pageSize).ToList();
    }
}

Переменная pageSize указывает, сколько элементов будет на странице. Метод Index получает номер страницы, и по нему отдает нужные данные.

При первом обращении к сайту метод Index будет возвращать представление, в которое будет передаваться результат функции GetItemsPage()

Функции GetItemsPage() по сути выполняет пагинацию данных, выбирая ту часть, которая соответствует номеру странице и количеству элементов на странице.

Если же запрос представляет Ajax-запрос, то метод Index возвращает частичное представление _Items, в которое опять де передается результат функции GetItemsPage().

Создадим частичное представление "_Items.cshtml":

@model IEnumerable<InfiniteScrollApp.Models.Phone>

@foreach (var item in Model)
{
    <div>
        <h3>@item.Name</h3>
        <p>@item.Company</p>
    </div>
}

Оно выводит список переданных в него объектов.

И создадим главное представление Index.cshtml:

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title - My ASP.NET Application</title>
</head>
<body>

<div id="scrolList">
    @Html.Partial("_Items")
</div>

<div id="loading"><img src='@Url.Content("~/Content/loading_spinner.gif")'></div>

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
<script type="text/javascript">
$(function () {

    $('div#loading').hide();

    var page = 0;
    var _inCallback = false;
    function loadItems() {
        if (page > -1 && !_inCallback) {
            _inCallback = true;
            page++;
			$('div#loading').show();

            $.ajax({
                type: 'GET',
                url: '/Home/Index/' + page,
                success: function (data, textstatus) {
                    if (data != '') {
                        $("#scrolList").append(data);
                    }
                    else {
                        page = -1;
                    }
                    _inCallback = false;
                    $("div#loading").hide();
                }
            });
        }
    }
	// обработка события скроллинга
    $(window).scroll(function () {
        if ($(window).scrollTop() == $(document).height() - $(window).height()) {

            loadItems();
        }
    });
})
</script>
</body>
</html>

Для загрузки данных в представлении определен блок с id="scrolList". Он по умолчанию содержит вызвов частичного представления _Items.cshtml: @Html.Partial("_Items"), благодаря чему уже при первом обращении у нас будет некоторое начальное количество элементов.

И также здесь используется специальный блок с id="loading" для отображения индикатора загрузки с помощью gif-анимации:

gif-анимация

Всю основную работу делает javascript. Чтобы отследить прокрутку, применяем обработчик $(window).scroll(), который вызывает функцию loadItems()

В функции loadItems() с помощью ajax-запроса происходит подгрузка дополнительных данных.

Подгрузка данных в Web Api

В Web Api все будет аналогично, за исключением отправки данных. Допустим, у нас есть следующий контроллер Web API:

public class ItemsController : ApiController
{
    List<Phone> phones;
    const int pageSize = 8;
    public ItemsController()
    {
        phones = new List<Phone>
        {
            new Phone {Id=1, Name="Samsung Galaxy III", Company="Samsung"},
            new Phone {Id=2, Name="Samsung Galaxy IV", Company="Samsung"},
            //..............................................
            new Phone {Id=21, Name="LG G3", Company="LG"}
        };
    }
    [Route("api/items/get/{page}")]
    public IHttpActionResult GetItems(int page)
    {
        var itemsToSkip = page * pageSize;
        return Ok(phones.OrderBy(t=>t.Id).Skip(itemsToSkip).Take(pageSize).ToList());
    }
}

И загрузка данных на html-странице:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Прокрутка в Web API</title>
</head>
<body>
<div id="scrolList"></div>
<div id="loading"><img src='@Url.Content("~/Content/loading_spinner.gif")'></div>
 
@Scripts.Render("~/bundles/jquery")
<script type="text/javascript">
$(function () {
    $('div#loading').hide();

    var page = 0;
    var _inCallback = false;

    loadItems();

    function loadItems() {
        if (page>-1 && !_inCallback) {
            _inCallback = true;

            $('div#loading').show();

            $.ajax({
                type: 'GET',
                url: '/api/items/get/'+page,
                success: function (data, textstatus) {
                    if (data.length > 0) {

                        var htmlLine = "";
                        $.each(data, function (index, item) {

                            htmlLine += "<div><h3>" + item.Name + "</h3><p>" + item.Company + "</p></div>";
                        })
						$("#scrolList").append(htmlLine);
                        page++;
                    }
                    else {
                        page = -1;
                    }
                    _inCallback = false;
                    $("div#loading").hide();
				}
			});
		}
    }
    $(window).scroll(function () {
        if ($(window).scrollTop() == $(document).height() - $(window).height()) {

            loadItems();
        }
    });
})
</script>
</body>
</html>

В представлении все то е самое, только данные получаем не в виде частичного представления, а в виде объектов javascript.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850