Несколько недель назад читатель спросил, есть ли у меня пример бесконечной прокрутки с бэкэндом ColdFusion. Я ответил, что нет, и что бесконечный свиток — худшее, что могло случиться с Интернетом со времен горизонтального правила радуги.
Возможно, я немного чрезмерно драматичен, но я действительно не фанат этого. Может быть, это ОКР во мне, но тот факт, что я никогда не смогу добраться до конца бесконечного пользовательского интерфейса с прокруткой, просто чертовски раздражает меня.
Это сказанное — я понял — почему бы не сделать быстрый пример. Это не может повредить, верно?
Я немного погуглил по теме. Первоначально результаты, которые я нашел, были не очень полезны. Многим требовалось немного настройки, и я действительно искал что-то быстрое и простое. Наконец я наткнулся на этот замечательный ответ о переполнении стека:
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
//Add something at the end of the page
}
});
4 простых строчки. Ницца! Я взял это и побежал с этим. Сначала я создал поддельный сервис в компоненте ColdFusion, который будет возвращать бесконечный объем данных. Не совсем реальный мир, но это сработало. Обратите внимание, что я добавил немного задержки в код, чтобы локальное тестирование показалось мне более реалистичным.
component {
//default per page
variables.perpage = 25;
//json all the things
url.returnformat = "json";
remote function getData(numeric start = 1) {
//fake slowness
sleep(1000);
var results = [];
for(var i=1; i <= variables.perpage; i++) {
var result = { "title":"This Is Blog #start+i-1#", "body": repeatString("This is some random stuff. ", randRange(3,7)) };
arrayAppend(results, result);
}
return results;
}
}
Код здесь довольно произвольный. Я возвращаю массив структур, содержащих заголовок и тело. Я принимаю параметр запуска, но я даже не использую его. Опять же, единственной целью для этого было просто отправить мне много данных. Теперь давайте посмотрим на код переднего плана.
<!doctype html>
<html lang="en">
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(document).ready(function() {
//flag to detect already loading
var loading = false;
//initial position
var position = 1;
//a place for my crap
var contentDiv = $("#content");
//populate the initial content
loadContent(position);
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
loadContent(position);
}
});
function loadContent(s) {
if(loading) return;
loading = true;
contentDiv.append("<span class='loading'>Loading...</span>");
$.get("service.cfc?method=getData", {start:position}, function(res, code) {
//Lame dynamic output
var s = "";
for(var i=0, len=res.length; i<len; i++) {
s += "<h2>" + res[i].title + "</h2><p> " + res[i].body + "</p>";
}
contentDiv.find(".loading").remove();
contentDiv.append(s);
position += res.length;
loading = false;
},"json");
}
})
</script>
</head>
<body>
<div id="content"></div>
</body>
</html>
Чуть более 4 строк, но, надеюсь, вы увидите, что я просто взял логику из ответа Stack Overflow и обернул ее вокруг вызова функции loadContent. loadContent обрабатывает несколько вещей.
- Во-первых, он достаточно умен, чтобы распознавать, когда он выбирает данные, и предотвращать одновременное выполнение нескольких запросов XHR.
- Во-вторых, он обрабатывает обновление DOM с помощью сообщения о загрузке, чтобы вы знали, что важная хрень уже в пути.
- Он выполняет вызов XHR и обрабатывает его рендеринг. (Вставьте напоминание об использовании шаблонов JavaScript здесь.)
- Наконец это удаляет загрузочное сообщение.
В целом довольно просто. Вы можете продемонстрировать это здесь: http://www.raymondcamden.com/demos/2013/may/21/test.html . Если это кажется медленным, помните, что я оставил там команду sleep ().
Я создал второе демо, которое использует мою реальную базу данных блогов. По большей части это то же самое, но обратите внимание на использование операций Query и limit для пейджинга данных.
component {
//default per page
variables.perpage = 25;
//json all the things
url.returnformat = "json";
remote function getData(numeric start = 1) {
var q = new com.adobe.coldfusion.query();
q.setDatasource("myblog");
q.setSQL("select title, posted, left(body,250) as excerpt from tblblogentries order by posted desc limit #val(arguments.start)-1#,20");
var rows = q.execute().getResult();
var results = [];
for(var i=1; i<=rows.recordCount; i++) {
arrayAppend(results, {"title":rows.title[i], "posted":rows.posted[i],"excerpt":htmlEditFormat(rows.excerpt[i])});
}
return results;
}
}
Вы можете попробовать эту версию здесь: http://www.raymondcamden.com/demos/2013/may/21/test2.html
В моем тестировании это загрузилось довольно быстро (и я сейчас на VPN, загружаю 2 гигабайта виртуальных машин). В этой версии не хватает двух вещей.
Первый — мне нужно разрешить моей внешней службе распознавать, когда она больше не получает строки данных от внутренней части. Я мог бы справиться с этим с флагом в объекте результата или другим способом.
Второе. Если бы я добавил ссылки на реальные записи в блоге, мне нужно было бы поддерживать способ помнить, где вы были, когда нажимали кнопку «Назад».
Если люди будут заботиться, я сделаю некоторые обновления, чтобы добавить это.
