Выводим изображения Gallery с помощью Ajax с подгрузкой по кнопке

Выводим изображения Gallery с помощью Ajax с подгрузкой по кнопке

Здесь представлю решение для вывода изображений, добавленных в Gallery (или другого подобного компонента) MODX, с использованием Ajax, разбивкой изображений на колонки (в итоге получим что то вроде вертикальной Masonry-раскладки). Здесь предусмотрено использование изображений разной высоты и их автоматический разброс по колонкам таким образом, что бы блок с изображениями был заполнен максимально (в этой части сильно не усложнял, если получится колонка сильно длинее соседних - нужно немного изменить порядок изображений в галерее.. буквально 1-2 картинки подвинуть). Заполняется первая строка, если картинок на вторую строку достаточно - вторая, если нет - заполняются наименьшие по высоте колонки.

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

Изображения будут загружаться одинаковыми частями, вызовом функции по кнопке "больше", или при загрузке страницы, прокрутке, другом событии.

Для нормальной работы (как задумано) понадобится:

  • Компонент (приложение) Gallery (можно любую другую галерею, обращаться к БД за картинками будет из сниппета, нужно только запрос переделать)
  • phpthumbof, или phpthumbon (или что то аналогичное), для изменения размера изображений
  • Написать небольшой сниппет
  • GIF-ка для анимации загрузки, например: анимация загрузки
  • Создать ресурс с вызовом этого сниппета
  • Добавить функцию JS
  • Добавить небольшой блок на страницу и вызвать функцию

Вот и все. Поехали!

HTML код блока для изображений

<section class="photog">
    <div class="title">Фотогалерея</div>
    <div class="items"></div>
    <div class="text-center"><button class="btn btn-primary" onclick="getAjaxAlb();">Загрузить ещё</button></div>
</section>

Здесь интересного мало, есть блок с классом "items", именно в нем будем создавать колонки, в которые будут загружаться изображения. Так же есть кнопка, на которую повесим событие "onclick"

JS

Теперь функция getAjaxAlb, которая и будет выводить изображения. Разместить можно как в коде страницы, так и в отдельном файле, никаких переменных из CMS здесь нет.

Здесь не лишним будет рассказать о некоторых переменных, параметрах:

  • start - количество изображений, которые уже есть на странице, используется при подгрузке новых изображений по кнопке. Используется в сниппете
  • limit - количество изображений, загружаемых за 1 раз
  • n_col - количество колонок. Разное для разных разрешений экрана.
  • w - ширина изображений. Разная для разных разрешений экрана. Передается в сниппет и используется как параметр phpthumbof (-on)
  • alb - ID альбома Gallery
  • n_itm - количество полученных изображений (не всегда равно лимиту)
  • n_itm_cur - количество изображений, еще не распределенных по колонкам (когда таких изображений становится меньше чем колонок, распределяем оставшиеся по колонкам с наименьшей высотой)
  • col - текущая колонка, куда будет вставлено изображение
  • hgs - массив с высотами колонок

Некоторые пояснения будут прямо в коде:

function getAjaxAlb() {
	$('.photog .btn').hide().after('<img src="loading.gif" class="loading" alt="Загрузка" />');/*Скроем на время кнопку, вместо нее покажем анимацию*/
	var start = $('.photog .column img').length;
	var oknow = document.documentElement.clientWidth;
	/*Параметры для разных разрешений экрана*/
	if (oknow > 1200) {
		var n_col = 4;
		var w = 440;
		var limit = 9;
	}
	if (oknow > 600 && oknow < 1201) {
		var n_col = 3;
		var w = 400;
		var limit = 9;
	}
	if (oknow < 601) {
		var n_col = 2;
		var w = 300;
		var limit = 6;
	}
	$.ajax({
		url: '/ajaxfoto',
		type: 'post',
		data: {
			alb: '1',
			limit: limit,
			start: start,
			width: w
		},
		dataType: 'json',
		beforeSend: function() {
			$(this).html('loading');
		},
		complete: function() {
		},
		success: function(json) {
			var n_itm = json.length;
			var n_itm_cur = n_itm;
			var col = 0;
			var hgs = Array();
			
			if (start == '0') {
				/*Если это первая загрузка - добавим колонки и начнем подсчет их высоты*/
				for (i = 0; i < n_col; i++) {
					$('.photog .items').append('<div class="column"></div>');
					hgs[i] = 0;
				}
			} else {
				/*Иначе, просто посчитаем высоту колонок*/
				i = 0;
				$('.photog .column').each(function() {
					hgs[i] = $(this).height();
					i++;
				});
			}
			$(json).each(function() {
				$('.photog .column').eq(col).append('<img src="'+this['file']+'" alt="" />');
				hgs[col] += this['height'];/*Для подсчета высоты колонок решил использовать такой вариант, как наиболее точный, учитывая одинаковую ширину изображений*/
				/*Перейдем к следующей колонке*/
				col++;
				/*Изменяем количество оставшихся картинок*/
				n_itm_cur--;
				if (col == n_col) {
					/*Если одна строка заполнена, переходим к первой*/
					col = 0;
				}
				if (n_itm_cur < n_col) {
					/*Если картинки заканчиваются, распределяем среди наименьших колонок (учитывая разную высоту изображений, так будет немного ровнее)*/
					var h = hgs[col];
					for(i=0;i<n_col;i++) {
						if (hgs[i] < h) {
							h = hgs[i];
							col = i;
						}
					}
				}
			});
			if (n_itm == limit) {
				$('.photog .btn').show();/*Если изображений все еще достаточно - покажем кнопку*/
			}
			$('.photog .loading').remove();
		}
	});
}

Сниппет и ресурс с вызовом

Здесь для начала создадим ресурс для вызова сниппета, к которому будет обращаться скрипт. В моем случае это ресурс, который:

  • Опубликован
  • Скрыт из меню
  • URI: ajaxfoto
  • Содержимое (вызов сниппета. Вызывать придется некешированным):
  • Шаблон: пустой

Теперь осталось создать сниппет с именем getGalImgsAj и вот таким содержимым:

<?php
$alb = (int)$_POST['alb'];
$limit = (int)$_POST['limit'];
$start = (int)$_POST['start'];
$width = (int)$_POST['width'];
$json = array();


$sql = "SELECT i.filename FROM modx_gallery_album_items ai LEFT JOIN modx_gallery_items i ON (i.id = ai.item) WHERE ai.album = '" .  $alb . "' ORDER BY ai.rank LIMIT ".$start.", ".$limit;
$sel_imgs = $modx->query($sql);
$imgs = $sel_imgs->fetchAll(PDO::FETCH_ASSOC);
foreach ($imgs as $img) {
    $file = 'assets/gallery/'.$img['filename'];
    $options = 'w='.$width.'&zc=0';
    $image = $modx->getOption('site_url').$modx->runSnippet('phpthumbof', array('input' => $file, 'options' => $options));
    list($width, $height) = getimagesize($image);
   $json[] = array(
       'file' => $image,
       'height' => $height
       );

}
return json_encode($json);

Немного CSS

.photog .items {margin-left:-4px;margin-right: -4px;overflow-x: hidden;}
.photog .items:after {content: '';clear:both;display: block;}
.photog .column {width:25%;box-sizing:border-box;float:left;}
.photog .column img {width: 100%;border:4px solid #fff;box-sizing: border-box;}
@media all and (max-width: 1200px) {
.photog .column {width:33.3333%;}
}
@media all and (max-width: 600px) {
.photog .column {width:50%;}
}

Пример

Наведите на блок для первой загрузки (сделал первую загрузку по .hover())

Комментарии ()