Статьи

Пример бесконечной прокрутки с ColdFusion

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

Первый — мне нужно разрешить моей внешней службе распознавать, когда она больше не получает строки данных от внутренней части. Я мог бы справиться с этим с флагом в объекте результата или другим способом.

Второе. Если бы я добавил ссылки на реальные записи в блоге, мне нужно было бы поддерживать способ помнить, где вы были, когда нажимали кнопку «Назад».

Если люди будут заботиться, я сделаю некоторые обновления, чтобы добавить это.