Несколько недель назад читатель спросил, есть ли у меня пример бесконечной прокрутки с бэкэндом 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 гигабайта виртуальных машин). В этой версии не хватает двух вещей.
Первый — мне нужно разрешить моей внешней службе распознавать, когда она больше не получает строки данных от внутренней части. Я мог бы справиться с этим с флагом в объекте результата или другим способом.
Второе. Если бы я добавил ссылки на реальные записи в блоге, мне нужно было бы поддерживать способ помнить, где вы были, когда нажимали кнопку «Назад».
Если люди будут заботиться, я сделаю некоторые обновления, чтобы добавить это.