Ajax бесконечная загрузка товаров virtuemart 2.x + joomla 2.5.x — модуль
Возникла идея реализовать для одного из проектов бесконечную подгрузку товаров и просмотр бесконечного ассортимента. Сам сайт реализован на joomla 2.5.9 с установленным virtuemart 2.20b. В целом моя реализация должна без проблем работать и на других версиях Joomla 2.5.x. В этой статье мы пройдемся по всем основным моментам создания компонента.
Структура модуля
Я не буду затрагивать устройства таких файлов как index.html и составления xml описания файла, при необходимости вы можете скачать или посмотреть модуль на гитхабе. Остановлюсь лишь на основных файлах.
- mod_manylazy.php — точка входа в наш модуль
- helper.php — содержит функции нашего модуля
- tmpl/default.php — шаблон вывода
- ajax.php — обработка ajax запросов в модуле
Сам модуль не претендует на готовое решение и должен настраиваться вывод товаров для каждого магазина в отдельности в зависимости от шаблона, я постарался сделать все максимально простым и понятным для редактирования.
Начнем с точки входа в наш модуль файл mod_manylazy.php
1 2 3 4 5 6 7 8 9 | defined('_JEXEC') or die('Restricted access'); // Подключение файла helper.php require_once JPATH_BASE.'/modules/mod_manylazy/helper.php'; //Сколько показывать в начале. $prod_count = $params->get('prod_count'); //Подключаем шаблон mod_manylazy require(JModuleHelper::getLayoutPath('mod_manylazy')); |
Ничего особенного, все остальное мы будем делать в helper.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | defined('_JEXEC') or die('Restricted access'); /** * Lazy load ддя продуктов virtemart 2 и joomla 2.5.x. * by webislife.ru */ class ModManyLazyHelper { // Получаем продукты из базы данных в определенном количестве. public static function getProdsRand($col) { //Таким вот запросом, получаем имя товара, имя категории товара, его цену и ссылку на изображение товара из разных таблиц. $sql_query = "SELECT catru.category_name, cat.virtuemart_category_id, pru.virtuemart_product_id, pru.product_name, pm.file_url, pri.product_price FROM #__virtuemart_product_categories AS cat INNER JOIN #__virtuemart_categories_ru_ru AS catru ON (catru.virtuemart_category_id = cat.virtuemart_category_id) INNER JOIN #__virtuemart_products_ru_ru AS pru ON (pru.virtuemart_product_id = cat.virtuemart_product_id) INNER JOIN #__virtuemart_product_medias AS med ON (med.virtuemart_product_id = cat.virtuemart_product_id) INNER JOIN #__virtuemart_medias AS pm ON (pm.virtuemart_media_id = med.virtuemart_media_id) INNER JOIN #__virtuemart_product_prices AS pri ON (pri.virtuemart_product_id = cat.virtuemart_product_id) ORDER BY RAND()"; $db = JFactory::getDbo(); //Выполняем запрос с ограничением $col $db->setQuery($sql_query,0,$col); //Для удобства пройдемся по полученным объектам и представим удобный массив для будущих ссылок //Все это сделано в основном ради убирания .0000 у цены и построения правильных SEF ссылок в нашем магазине $prods = array(); foreach ($db->loadObjectlist() as $key => $p) { $product = array(); $product['name'] = $p->product_name; $product['cat_name'] = $p->category_name; $product['cat_url'] = JRoute::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id='.$p->virtuemart_category_id); $product['product_url'] = JRoute::_('index.php?option=com_virtuemart&view=productdetails&virtuemart_product_id='.$p->virtuemart_product_id.'&virtuemart_category_id='.$p->virtuemart_category_id); $product['price'] = round($p->product_price); $product['image_url'] = $p->file_url; $prods[$key] = $product; } //Возвращаем массив товаров return $prods; } //Простенькая функция для получения того же количества товаров из бд, только в json виде. public static function getJsonProds($col) { return json_encode(self::getProdsRand($col)); } } |
Логика модуля очень проста. Мы подтягиваем из базы данных информацию о товаре, имя, цену, категорию, формируем SEF ссылки и все упаковываем в массив. Для будущих ajax запросов дописываем простенькую функцию. Для выполнения ajax запросов в модулях joomla 2.5 к сожалению каких-то стандартизированных решений нет и я использовал универсальный метод с обращением к joomla.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //Объявлем необходимые константы для нормальной работы с Joomla define('_JEXEC', 1); define('JPATH_BASE', dirname(__FILE__) . '/../..' ); define('DS', DIRECTORY_SEPARATOR); //Подключаем необходимы для работы файлы require_once(JPATH_BASE.DS.'includes'.DS.'defines.php'); require_once(JPATH_BASE.DS.'includes'.DS.'framework.php'); //Отслеживаем инициализацию сайта JFactory::getApplication('site')->initialise(); //Подключаем хелпер нашего модуля require_once JPATH_BASE.'/modules/mod_manylazy/helper.php'; //Получаем сколько нам надо товаров за раз. $prods = ModManyLazyHelper::getJsonProds(8); //Для ускорения процесса умираем с выдачей результата die($prods); |
Вот и все обработка запроса. Теперь перейдем непосредственно к шаблону и javascript коду.
В шаблоне default.php изначально вызываем нашу функцию из хелпера и получаем первые товары. Далее массивом в html выводим наши товары.
1 2 3 | defined('_JEXEC') or die('Restricted access'); //Получаем товары $prods = ModManyLazyHelper::getProdsRand($prod_count); |
Вот html шаблон. В моем случае по умолчанию блок спрятан и только после клика по ссылке «Перейти к бесконечному просмотру» мы добавляем слушатель события для window.scroll и показываем основной контейнер. Суть автоподгрузки проста, как только в поле зрения попадает блок «Загружаем еще» мы отправляем ajax запрос к серверу на получение новых случайных товаров и выводим их через javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <div class="row-fluid"> <div class="span12"> <div class="lazy_start_show">Посмотреть бесконечный ассортимент!</div> </div> </div> <div class="row-fluid" id="main_lazy_container"> <div class="span12 lazy_container_prods"> <? foreach($prods as $p) { ?> <div class="lazy_block_product"> <div class="lazy_block_image image_cont"> <img src="<? echo $p['image_url']; ?>" alt="<? echo $p['name']; ?>"> </div> <div class="product_price_block"> <? echo $p['price'].' руб.'; ?> </div> <div class="product_title"> <p class="lazy_category_link"> Категория: <a href="<? echo $p['cat_url'];?>"><? echo $p['cat_name']; ?></a> </p> <a class="lazy_product_link" href="<? echo $p['product_url'];?>"><? echo $p['name']; ?></a> </div> </div> <? } ?> </div> <div class="span12"> <div class="lazy_loader_trigger"><p class="lazy_loader">Загружаем еще...</p></div> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | jQuery(document).ready(function($) { //Текущий статус загрузки, чтобы не плодить кочу запросов к серверу. Пока не выполнен один запрос, второй отсылать не будем. var currentload = false; //Наша функция подгрузки товаров var lazyLoader = function() { //Определяем высоту прокрутки var wt = $(window).scrollTop(); //Получаем позицию низа экрана var wb = wt + $(window).height(); //Получаем значение отступа нашего блока подгрузчика var lt = $('.lazy_loader_trigger').offset().top; //Если низ экрана стал ниже отступа блока подгрузчика и текущая загрузка не запущена if(wb > lt && currentload == false) { //Посылаем запрос $.ajax({ //Все стандартно, при необходимости можно и данные передать url: '/modules/mod_manylazy/ajax.php', type: 'POST', dataType: 'json', data: {}, success: function(data, status) { //Формируем html шаблон из возвращенного json ответа var html = ''; var l = data.length; for(var key in data) { var val = data[key]; //Иногда ответ может придти пустым... проверяем. if(val['price'] != undefined) { //Разметка html += '<div class="lazy_block_product">'; html += '<div class="lazy_block_image image_cont">'; html += '<img src="'+val['image_url']+'" alt="'+val['name']+'" /></div>'; html += '<div class="product_price_block">'+val['price']+' руб.</div>'; html += '<div class="product_title">'; html += '<p class="lazy_category_link">Категория: <a href="http://manytomany.ru'+val['cat_url']+'">'+val['cat_name']+'</a></p>'; html += '<a class="lazy_product_link" href="http://manytomany.ru'+val['product_url']+'">'+val['name']+'</a>'; html += '</div>'; html += '</div>'; } } //Добавляем новые блоки $('.lazy_container_prods').append(html); currentload = false; }, //Перед отправкой показываем лоадер before: function() { $('.lazy_loader').show(); currentload = true; }, //Ошибку просто выводим в консоль error: function(data) { console.error(data); } }); } } //По клику приступить к просмотру, добавляем событие на скролл окна и показываем контейнер с товарами $('.lazy_start_show').on('click', function() { $('#main_lazy_container').show(300); $(window).on('scroll', lazyLoader); }); }); |
CSS Разметку я приводить не буду и в модуле ее по умолчанию нету т.к. этот момент на мой взгляд сугубо индивидуальный и установка с настройкой подобного модуля подразумевает присутствие у вас некоторых навыков в HTML, javascript и php. Посмотреть пример работы модуля вы можете на сайте manytomany.ru скачать и ознакомиться с кодом вы можете на github
Комментарии