Как сделать каталог товаров в html
Как сделать каталог товаров в html
Верстка интернет-магазина: список товаров
Требования к верстке каталогов интернет-магазинов имеют свойство повторяться из проекта в проект. Поэтому у меня выработался набор стандартных приемов, которыми я хочу поделиться в этой статье.
Некоторые приемы уже были рассмотрены в различных статьях. Однако у меня возникло желание объединить их и проиллюстрировать отдельными демо. Надеюсь, в таком виде наработки окажутся полезны верстальщикам, которым часто приходится работать над интернет-магазинами.
В качестве примера мы будем верстать список товаров для интернет-магазина комнатных растений. Демо готового каталога можно посмотреть по ссылке. В результате должен получиться список растений с фото, описаниями и всплывающими кнопками. Кроме того, вид списка можно будет переключать: товары будут выглядеть либо как плитка, либо как таблица.
Адаптивная сетка
Итак, начнем с создания адаптивных плиток — будущих карточек товаров. У нас будет 8 комнатных растений:
Оберткой для товаров послужат блоки, занимающие 100% ширины родителя на мобильных устройствах.
Теперь используем медиа-запросы, чтобы разместить по две, три и четыре плитки в ряд при больших разрешениях монитора.
И зададим стили карточек товаров.
Исправим это с помощью отрицательного значения margin-right у родителя.
Теперь все в порядке. Посмотреть на получившуюся сетку можно на страничке демо. Для наглядности блокам в демо задана фиксированная высота.
Фото товаров
Следующим интересным моментом является верстка блоков с фотографиями растений. Разметка в данном случае будет такой:
Сделаем родителя тега img квадратом с помощью свойства padding-bottom со значением 100%. Вот все стили для данного блока.
В указанном блоке расположим картинку таким образом, чтобы при любых размерах она не выходила за пределы родителя, и отцентрируем ее горизонтально и вертикально.
Осталось немного увеличивать фото при наведении.
Как все это работает можно посмотреть на примере демо.
Описание товара
А эффекта размытия последних букв четвертой строки мы добьемся с помощью псевдоэлемента :after с линейным градиентом в качестве фона.
Перечеркнутые цены
Всплывающие кнопки
Чтобы лучше разобраться с кнопками, можно посмотреть это демо.
Переключение вида карточек товаров
Для переключения между плиткой и табличным видом каталога мы создаем две кнопки.
Далее абсолютно позиционированные элементы занимают свое «естественное» положение. Например, так происходит с кнопками.
Это был последний момент, которым хотелось с вами поделиться. С праздниками и всего доброго.
Фильтры в интернет-магазине. Урок 2. Структура проекта и верстка
Переходим ко второй части наших уроков. Здесь рассмотрим структуру проекта, его файлов и папок, сверстаем блоки с фильтрами, товарами и подключим плагин jQueryUI.slider для регулировки цен.
Структура файлов и папок
Те, кто читал мои предыдущие статьи про корзину и отправку заказа, ничего нового не увидят. Если Вы с этими постами не знакомы, то кратко структура представляется так.
В файле js/modules/main.js подключаются и инициализируются все модули, в том числе и наш новый catalogDB. Для его подключения в main.js нужно будет написать пару строк.
В файле css/main.css находятся немногочисленные стили. В целом, мы вполне обойдемся и bootstrap.
В папку scripts закинем файл catalog.php, который будет выполнять всю серверную работу.
А теперь последовательно.
Базовый файл catalog.html
Секция head ничем не отличается от других страниц нашего магазина. Для body навесим атрибут data-page=»catalogDB» (это по аналогии с предыдущими страницами, чтобы отличать их друг от друга). Содержимое body будет простым.
Пока ничего хитрого. Заголовок h2, меню nav nav-pills и два контейнера для фильтров и списка товаров. Ими мы займемся чуть позже. В списке товаров будет крутиться гифка до тех пор, пока не загрузятся данные с сервера.
Заготовка модуля catalogDB.js
Сильно мудрить не будем и пойдем по стопам и примерам предыдущих статей. Объявим модуль-переменную catalogDB и заведем в ней пока единственную функцию init, которую экспортируем во внешний мир. В init будет для начала строчка вывода в консоль соответствующего сообщения. Дальше, конечно же, ее расширим.
Редактируем главный модуль main.js
Мы просто запускаем catalogDB.init и инициализируем корзину с настройками, как на самой первой странице каталога.
Если все сделали правильно, то увидите примерно такую картину
Верстаем панель фильтров
Для начала добавим контейнерам filters и goods бутстраповские классы col-md-12, дабы они занимали всю доступную ширину. И добавим между ними парочку переносов строк, если прямо сейчас не хотим возиться с css.
А в filters уже напишем основную верстку
Верстка стандартная, на что стоит обратить внимание, так это на id, data-атрибуты, классы c js-префиксом и атрибуты name. Все эти данные будут использоваться в дальнейшем в js-коде или участовать в формировании данных для отправки на сервер (как атрибуты name).
Понятно, что пока все данные захардкожены. Категории, бренды и цены будут подтягиваться с сервера и выглядеть прилично. Я сознательно подготовил сначала всю верстку, чтобы потом не отвлекаться на нее при разработке js-кода. А пока это выглядит так
Как Вы могли заметить, вместо обещанного слайдера для цен стоят обычные числа, разделенные обычными дефисом. Сейчас мы это исправим.
Подключаем слайдер jqueryUI
Для начала создадим объект ui, в котором закешируем нужные dom-элементы.
_initPrices выполняет саму инициализацию слайдера (взято из документации jqueryUI). В параметре options мы передаем минимальное и максимальное значение для слайдера. Опция slide содержит функцию _onSlidePrices, вызываемую при изменении позиций слайдера. В _onSlidePrices пишем код, который перерисовывает метку с указанием диапазона цен и устанавливает значения для скрытых инпутов min-price и max-price. А в методе init мы просто запустим _initPrices с левыми настройками 5000 и 50000.
Слайдер подключен, можете поиграть с ним и наблюдать, как меняются значения цен
Верстаем список товаров
Товары у нас будут очень похожи на уже упоминаемый каталог из статьи про корзину в интернет-магазине. Разве что чуть компактнее для экономии места. Добавим в разметку верстку для одного товара. Смотрим html-код.
data-атрибуты ровно такие же, какие и нужны для возможности добавления товаров в корзину. Картинки для всех товаров Вы найдете в исходниках (ссылка будет после публикации всех уроков). И последним штрихом добавим немного css-кода в файл css/main.css. Необязательно, но для небольшой красоты пусть будет.
Наконец наша верстка полностью готова, результат видим ниже
Подведем итоги
На этом уроке мы сверстали весь интерфейс фильтров и товаров нашего интернет-магазина, практически не написав свои стили. Этим мне и нравятся фреймворки вроде bootstrap, которые позволяют быстро накидать прототип страницы, довольно простой, но притом не самый страшный.
Верстать нам больше не придется, следующий урок будет о том, как собрать все нужные данные на клиенте, как отправить их на сервер и вернуть какой-то результат. А пока можете вспомнить предыдущий урок про структуру базы данных. Она нам еще пригодится при написании серверного кода.
Создание страницы товара с интерактивными цветами с помощью HTML, CSS3 и jQuery
В этом уроке мы собираемся создать страницу товара для сайта с использованием HTML, CSS3 и jQuery. Вы можете использовать ее, чтобы показать товары на сайте вашего интернет-магазина.
В уроке, мы будем использовать шрифты Google, Roboto если точно. Убедитесь, что шрифт подключен, прежде чем начинать.
Первым шагом, мы создадим HTML структуру. Вот то, что нам нужно:
Окей, давайте обернем всё классом `.container`.
Beats EP
Теперь, давайте перейдем к следующему шагу и настроим внешний вид.
Добавляем основные стили для body.
Обратите внимание, что классу `.container` задано свойство `display: flex` для выравнивания колонок.
Теперь, давайте добавим некоторую ширину колонкам и свойство `position: relative` для класса `.left-column`, потому что мы будем использовать свойство `position: absolute` для абсолютного позиционирования изображений.
Здорово! Теперь добавим стили для первой колонки с классом `.left-column`. В этой колонке у нас есть три изображения, трех наушников с разным цветом. Прописываем изображениям свойство `opacity: 0`, также изображениям нужно добавить класс `.active` и прописать свойство `opacity: 1`, нам понадобится это позже, когда мы будем работать с jQuery.
Теперь настроим стиль для правой колонки с классом `.right-column`. Начнем с класса `.product-description`, где расположено описание товара.
Теперь, нам нужно настроить стили цветовых конфигураций товара.
Здесь у нас есть три радиокнопки, давайте оформим их, чтобы они выглядели красиво. Каждая радиокнопка будет иметь цвет, который соответствует цвету наушников. Мы будем использовать `: checked` для добавления отмеченной иконки,`: checked` — это замечательное псевдосостояние, которое предоставляет CSS.
Отлично! Теперь, давайте зададим стили классу `.cable-configuration`, раздела конфигураций. Здесь у нас есть три кнопки и ссылка. Давайте настроим стили состояний и сделаем их красивыми.
Последнее, что нужно сделать в этой колонке, настроить стиль секции с ценой товара, ей задан класс `.product-price`.
Замечательно! Вот финальный результат того, что мы делали:
Также давайте добавим адаптивность.
Последнее, что мы должны сделать, это настроить смену изображения, когда мы нажимаем на цвет, так чтобы при изменении цвета радиокнопки, он соответствовал цвету наушников. Здесь используется jQuery, поэтому убедитесь, вы включили его в проект. Мы будем использовать атрибуты данных для работы с ним.
Обратите внимание, что мы добавляем класс `.active`. Как я упоминал ранее, каждый раз при нажатии на соответствующий цвет.
Посмотреть демо и скачать страницу товара веб-сайта
Потрясающе! Мы закончили! Не стесняйтесь использовать исходники в своих проектах. Взгляните на демонстрацию и сообщите нам, что вы об этом думаете в комментариях.
Постраничная навигация по товарам в интернет-магазине
Когда в интернет-магазине набирается хотя бы 3 десятка товаров, встает вопрос: как удобнее выводить списки товаров посетителям? Пока преобладают 2 способа: постраничное разбиение и динамическая подгрузка по мере прокрутки страницы. Впрочем, реализация обоих вариантов ничем особенно не отличается, кроме небольших изменений в javascript-коде.
Что сделаем и как это выглядит
В нашем демо интернет-магазина появится новая страничка, где мы и продемонстрируем пагинацию. Вот так это будет выглядеть.
Внешний вид скопирован с соседней страницы «Каталог с фильтрами». Я вообще хотел сначала встроить пагинацию в существующий каталог, но подумал, что там кода и так довольно много. Добавив еще и пагинацию, фильтры покажутся сложнее, чем они есть. Поэтому пусть это будет новая страница с минимальным функционалом, где мы сосредоточимся именно на навигации.
Создаем новую страницу
У тега body файла catalog-pag.html пишем атрибут data-page=»catalogPag». В самом же body вот такое меню и пустой список
Все стандартно: меню копипастим с любой предыдущей страницы, раздел goods из catalog.html. В catalogPag.js пока сделаем заготовку, чтобы просто работало
И подключим этот модуль в main.js, добавив в функцию init такие строки
Верстка
Нам нужно сверстать кнопки категорий, селект выбора количества страниц, пагинацию и информационное сообщение. Как всегда, не заморачиваемся, bootstrap в руки и вперед. Добавим такой участок между меню и списком товаров.
Ничего необычного. Разве что хочу пояснить про саму навигацию. В примере верстки у нас 3 страницы, причем 3-я как раз активная. Как именно строить навигацию, дело Ваше, но я приведу максимально возможный упоротый вариант. Это кнопки «В начало», «Предыдущая страница», собственно кнопки-номера страниц, «Следующая страница» и «В конец». Так как последняя страница сейчас активна, то кнопки «следующая» и «в конец» мы не показываем. Вы же можете их отрисовывать, но делать недоступными или придумать что-то еще. В общем, для примера делаем по максимуму, в реальном случае лишнее отрубите.
Шаблон underscore для вывода товаров
А его мы просто скопипастим со страницы catalog.html
Теперь вроде бы стоит писать js-код, собирать данные со страницы и отправлять их на сервер. Но сегодня мы разнообразия ради нарушим эту традицию и сначала напишем серверный код. Когда мы вернемся к javascript-у, у нас будет полностью готов бекенд и отдача товаров.
Серверная часть: выносим общий код
Небольшой оффтоп. Когда я начинал писать статьи про интернет-магазины, то не подозревал, в какой проект это выльется. И серверный код с точки зрения его структуры был совершенно простой. До такой степени, что подключение к mysql просто копировалось из файла в файл. Теперь это меня достало и пора безобразие исправить.
Старый код трогать не будем, но для нового сделаем отдельный файлик common.php (какое великолепное название!). В этот файл будем закидывать общие функции-хелперы и константы, нужные для всего магазина. Начнем с подключения к базе данных.
Копипастим этот код в последний раз, больше не придется. В следующий уроках common.php нам еще пригодится. И теперь дело посерьезнее: нужно написать скрипт, вытаскивающий товары с учетом фильтра по категории и разбиения по страницам.
Серверная часть: разбиение по страницам
Давайте подумаем, что будем делать в целом. Для начала создадим для скрипта отдельный файл catalog_pag.php.
Что нужно на выходе? Во-первых, сам список товаров. Во-вторых, нам обязательно нужно знать, сколько всего товаров попадают под дополнительные условия (в нашем случае, категория). Общее количество товаров нужно для определения числа страниц в навигации и для информирования покупателей. Всем этим будет заниматься клиент, от сервера же требуется только одно число.
В целом определили, что нужно, приступим к коду. Сначала общий вид catalog_pag.php
Давайте еще раз подумаем (что-то часто сегодня приходится думать), как удобнее написать код. Нам нужно выдернуть из базы 2 вещи. Первое: массив товаров нужной категории. Но не все товары, а только определенное количество (limit), начиная с нужной страницы (page). И второе: количество всех товаров из этой категории, но уже без учета пагинации.
Сразу напрашивается мысль, что для этого нужно 2 запроса. Мысль правильная, другое дело, как эти запросы составить? Давайте попробуем решить задачу в лоб. Упростим условия и напишем пару sql-запросов. Вот так бы мы выбрали 5 товаров из базы, начиная с 10го, причем отсортированных по цене.
Ничего сложного. А вот так мы вытащим количество всех товаров с указанной категорией
Тоже не код богов, а вполне обычный запрос. А теперь присмотримся: в скобках в качестве подзапроса мы указали очень знакомую строку
И мы понимаем, что в качестве queryBase можно указать сколь угодно сложный запрос с кучей фильтров и перекрестных таблиц. В нашем примере queryBase будет довольно простой, но на практике Вам придется писать запросы посложнее. Ничего страшного, составляйте какие угодно выборки, а потом подставляйте полученное в указанную схему. В нашем случае итоговый код вытаскивания товаров такой.
Если Вам непонятны названия таблиц, полей, откуда вообще все это взялось, крайне рекомендую к прочтению серию статей про фильтры в интернет-магазине. Общие принципы пагинации можно понять и без этого, но разобрать весь код без предыдущих уроков будет сложно.
А если Вы уже разбирали оные статьи, то видите, что кода меньше и он проще 🙂
Клиентская часть: первичный рендер каталога
Базовая структура catalogPag.js у нас есть, давайте наполним ее полезной начинкой. Сначала выделим все нужные dom-элементы и underscore-шаблон в отдельные переменные.
Действуем так. Сначала из функции init уберем тестовый console.log и вместо нее напишем вызов функции получения данных с сервера
Теперь реализация _getData()
Это обычный ajax-запрос на уже написанный php-скрипт. Сначала в _getOptions собираем данные для скрипта, потом отправляем запрос. В колбэке success проверяем код ответа, и если он равен «success», то вызываем _renderCatalog с товарами. Вот реализация _getOptions
Шаблон underscore у нас уже есть, данные с сервера есть, осталось только отрендерить html с этими данными и полученную разметку подставить в контейнер ui.$goods.
С базовым рендером все. Обновите страницу и увидите отрисованный каталог. Впрочем, мы уже видели его на соседних вкладках, поэтому пока интересного мало. Давайте лучше разберемся непосредственно с пагинацией.
Пагинация, преобразуем верстку в шаблон underscore
Вспомним, как выглядит верстка пагинации
Первая кнопка «В начало», вторая «Предыдущая», далее рисуется по кнопке на каждый номер страницы. «Следующая» и «В конец» не отрисованы, потому что 3 (она же последняя) кнопка активна. Дальше нее уже не пройдешь.
Теперь это добро нужно завернуть в underscore-шаблон. Чтобы полностью отрисовать такую систему, нам нужно знать номер текущей страницы и количество страниц в целом. Тогда мы сможем перебрать все варианты, поймем, выводить или нет крайние кнопки, ставить класс активности и прочее. Вот такой получится шаблон, который мы закинем в catalog-pag.html рядом с шаблоном товаров.
В первом условии проверяем, не первая ли страница нам попалась? Если не первая, то рисуем кнопку «В начало» с data-page=»1″ и «Предыдущая» с номером страницы на 1 меньше текущей.
И последний блок с кнопками «Следующая» и «В конец» выводится ровно по аналогии с начальным. С той разницей, что сравнение идет с последней страницей и следующая имеет номер page + 1.
Итак, немного вникнув в код, мы увидели, что ничего страшного в нем нет. Написано много, на деле все проще. Пора вдохнуть жизнь в этот шаблон и вместе с рендером товаров перерисовывать еще и пагинацию.
Рендер пагинации и информации о товарах
Дальше вызовем новую функцию _renderPagination после рендера товаров. Это будет в функции _getData в колбэке success. Для контекста приведу весь обновленный код.
После этого останется из этих переменных составить информацию goodsInfoMsg и закинуть текущую страницу с их общим количеством в шаблон pagTemplate. Уф, чтобы разобраться с этим, возможно, придется осмыслить код еще не раз, но я верю в Ваши силы. Вы уже молодец, что вообще добрались до этих строк 🙂
А если разбираться лень, то и фиг с ним, копипаст же никто не отменял. Эта штуковина просто будет работать. А мы же, слегка передохнув, перейдем к завершающей и самой веселой части. Вдохнем наконец жизнь в наше приложение, оживим кнопочки, переключалки и полюбуемся на плоды нашей работы.
Приложение оживает: подключаем события
У нас имеются 3 элемента интерфейса, которые ждут кликов: кнопки категорий, селект с выбором количества товаров на странице и сама пагинация. Общий код навешивания событий на оные элементы выглядит так
На каждый элемент по отдельной функции. Руки чешутся быстренько написать их реализацию, но!
Конечно, я по своей милой привычке обломаю читателя и обговорю еще одну деталь. Но без нее, друзья, не обойтись. Суть проста: при переключении категории или количества товаров на странице нам нужно сбрасывать номер текущей страницы на 1.
Итак, сбрасывать или нет текущую страницу, будут знать обработчики событий по элементам. А функции получения данных пусть об этом не думают, а получают на вход флаг resetPage, по которому определят, что страница должна быть сто пудов первая. Но с введением этого флага придется поправить код в нескольких местах.
Во-первых, в _getData. Теперь ее начало будет такое
Добавился на вход объект options, в котором лежит resetPage. Этот resetPage передадим в _getOptions. Во-вторых, чуть изменим саму _getOptions.
Мы говорим здесь, что при начальной загрузке страницы нам нужна первая страница и никакая иначе. С resetPage все. Как видим, отступление небольшое в плане кода, но про такие вещи забывать не стоит. Теперь нас ничего не удерживает от написания трех обработчиков событий. Весь код целиком
Код всех трех обработчиков очень похож. Меняем активную категорию или страницу и вызываем _getData, не забывая указывать, надо ли сбрасывать страницу на первую. А дальше _getData все сделает и отрисует сама. Вот теперь точно все!
Заключение
Несколько объемной получилась статья про пагинацию, но зато мы подробно рассмотрели весь процесс разбиения на страницы. И серверная, и клиентская части оказались вполне доступными для понимания. В предыдущих уроках приходилось писать вещи и посложнее. Впрочем, любая задача упрощается, когда начинаем подробно над ней размышлять и писать код.
Ссылки на демо и обновленные исходники интернет-магазина чуть ниже. Я завел для единообразия большие фиолетовые кнопки, чтобы было проще искать нужные ссылки 🙂
Как всегда, комментарии и вопросы не возбраняются.
Верстка каталога товаров ч.1
В этом уроке и в следующих 2-х будет верстаться каталог товаров.
Если у Вас нет верстки из бесплатных уроков уровня ПРОФЕССИОНАЛ, то можете скачать ее здесь — imdiz.ru/files/store.zip. Создайте папку store на компьютере и распакуйте скачанный архив в эту папку. У Вас должна получиться папка store со следующей структурой:
В первую очередь подключим правильно шрифт.
Как правильно подключать шрифты в HTML и CSS
Для правильного подключения шрифта нужно:
На уровне ПРОФЕССИОНАЛ шрифт подключался в style.css строкой:
Здесь путь до шрифта указан в строке src: url(https://imdiz.ru/files/store/fonts/Roboto.ttf);. Как видите шрифт подключается прямо с сайта imdiz.ru, и скачивать шрифт не надо.
А в только что скачанном Вами архиве imdiz.ru/files/store.zip путь до шрифта выглядит так src: url(../fonts/Roboto-Regular.ttf); (это в файле style.css в самом верху). Здесь шрифт уже находится в Вашей верстке. Находится он в папке fonts. Вы можете открыть Вашу папку fonts и увидите там несколько шрифтов, и один из них называется Roboto-Regular.ttf. Вообще в этой папке сейчас целое семейство шрифтов Roboto. Да, «семейство шрифтов» — это нормальный термин, используемый в сайтостроении и типографике.
Сразу разберу путь «url(../fonts/Roboto-Regular.ttf)». Эта строка находится в файле style.css, а он находится в папке css. Так вот, первые 2 точки означают — выйти из папки css. Затем слеш означает — зайти в папку fonts. Ну, а в папке fonts уже взять файл Roboto-Regular.ttf. То есть браузер при обработке верстки будет проходить именно такой путь, чтобы подключить нужный шрифт.
Такой путь «../fonts/Roboto-Regular.ttf» в CSS называется относительным. Так как он начинается относительно чего-то, в данном случае относительно файла style.css.
А вот путь «https://imdiz.ru/files/store/fonts/Roboto.ttf» называется абсолютным, так как в нем указан абсолютный адрес.
Шрифт подключен. Идем дальше.
Начало верстки каталога товаров
Теперь нужно сверстать новую страницу сайта с каталогом товаров.
Для сдачи заказчику или работодателю нужно готовить полную страницу. То есть нельзя сверстать только один каталог. Новая страница — это новый html-файл. Но шапка и подвал на всех сайтах одинаковые, поэтому в этот новый html-файл нужно будет скопировать верхушку и подвал верстки из index.html. СSS-файл останется тот же — style.css, он общий для всех страниц сайта. Новые стили нужно будет добавлять в этот же style.css.
Каталог товаров обычно представлен в 2-вариантах:
1-ый вариант:
В 1-ом варианте товары расположены в строку, а во 2-м — в столбец. Обычно в каждом интернет-магазине есть кнопки, чтобы расположить товары как Вы хотите. Обычно кнопки выглядят так: . И верстать нужно оба варианта. Часто верстаются 2 разных файла, например, products.html и products_row.html (row переводится как «строка»).
Начнем с создания нового файла.
Тег ul для верстки каталога товаров
О расположении товаров в столбец рассказывать особо нечего. При использовании тега карточки товаров итак расположатся сверху вниз, так как — это блочный элемент.
Больше интереса представляет собой расположение товаров в строку. Чтобы карточки встали в одну строку нужно использовать CSS-свойство flex.
Сперва сразу итоговые коды верстки products_row.html и style.css:
Ваш style.css можете полностью заменить.
В style.css новый код начинается после строки /* Products_row page */. Большие участки кода для новых страниц лучше комментировать для удобства. Но перед сдачей готовой работы все комментарии нужно удалять. Это считается хорошим тоном.
Добавьте коды в соответствующие файлы, сохраните (CTRL+S).
Для изображения товара сохраните себе эту картинку в папку img:
Откройте products_row.html в браузере. Перед Вами готовая верстка каталога товаров.
И здесь небольшое отступление. На уровне ПРОФЕССИОНАЛ не добавлена тень под полосой меню:
И это приближает обучение к реальным условиям, когда во время верстки проекта, что-то замечается не сразу, а потом редактируется.
Чтобы появилась тень в style.css изменен участок кода:
Добавить комментарий Отменить ответ
Начните зарабатывать версткой сайтов до 50 000 р./месяц уже через 5 дней
Каталог в интернет-магазине, переключаем внешний вид товаров одной кнопкой
В этой статье мы создадим набор переключателей внешнего вида каталога (можно даже назвать это темами). И небольшим бонусом научимся сохранять это состояние в localStorage. Так как html-разметка товаров у нас находится в underscore-шаблонах, то задача предельно упрощается. Это будет самый короткий и простой урок по интернет-магазинам. Приступим.
Что будем делать?
Давайте сразу посмотрим, что получится в итоге. На странице Каталог с пагинацией слева от категорий мы добавим 3 кнопки-иконки, которые и будут переключать внешний вид каталога. Это будут такие варианты: вид с большими фото, компактный вид (как на каталоге с фильтрами) и краткий список без фото (как раз он на скриншоте).
Нам нужно будет завести 3 underscore-шаблона под каждый вид и подключать их в зависимости от нажатой кнопки. Начнем с верстки.
Добавляем кнопки-иконки
Мне опять лень верстать что-то самому, поэтому для иконок воспользуюсь готовым bootstrap. Верстка получится такая. Я привел весь блок целиком: и категории, и новые кнопки-переключалки. Второй кнопке добавим класс active, пусть по умолчанию у нас будет вид компактный. То есть такой же, который мы создали в предыдущем уроке про постраничную навигацию
Готовим underscore-шаблоны
Осталось завести третий шаблон с кратким списком. Готового кода под него нет, но предлагаю не заморачиваться и написать что-то такое.
То есть просто выводим артикул, название товара и цену в строчку, не забыв нарисовать кнопку «Добавить в корзину». Никаких стилей специально делать не будем, для примера и так сойдет.
С шаблонами все, переходим на javascript.
Клиентский код для переключения внешнего вида каталога
Первое, добавляем новый элемент в объект ui
Второе, смотрим на переменную goodsTemplate, в которой у нас был записан единственный доселе шаблон. Теперь он у нас называется goods-template-compact, плюс есть еще 2 штуки. Давайте сделаем переменную goodsTemplate объектом, куда занесем все 3 шаблона.
Третье, в функции _bindHandlers нужно добавить обработчик клика на новые кнопки.
Четвертое, реализация функции клика _changeTheme
И пятое, в функции рендера каталога _renderCatalog нужно подставить шаблон с выбранным видом. В зависимости от нажатой кнопки. Это всего две строчки кода.
Вот и все! По сути всю работу за нас сделал underscore своими шаблонами. Как раз здесь и проявляется прелесть шаблонизации на клиенте. Очень приятная фишка с переключением обошлась нам довольно дешево в реализации.
И напоследок давайте добавим приятный бонус: научимся запоминать выбранную тему, чтобы после обновления страницы посетителю не пришлось заново выбирать понравившийся вид каталога.
Сохраняем выбранную тему в localStorage.
Сначала в функции смены вида каталога _changeTheme нужно записать выбранную тему в localStorage. Там добавилось всего 2 строки. Полный код функции теперь такой.
Теперь в функции init в самом начале, еще до загрузки и отрисовки каталога нужно вытащить тему из localStorage. Или, если там пока ничего нет, взять по умолчанию значение compact. Правим init
Теперь реализация _setTheme
P.S. Кстати, было бы неплохо сохранить в localStorage и количество товаров на странице, но предоставлю сделать это самим, аналогично с вышеразобранным примером 🙂
Подводим итоги
Немного планов на будущее
Как Вы могли заметить, тема интернет-магазинов после некоторого затишья начинает оживать. У меня появилось несколько интересных мыслей о новом и полезном функционале.
Возможно, статьи про магазин ждет небольшое изменение формата: есть мысль разбивать посты на очень короткие уроки, каждый из которых можно пройти минут за 5-10. Серия статей с фильтрами показала, что эта идея с разбиением удачная, но хочу попробовать сделать статьи еще меньше и легче в изучении. Как это получится на практике, посмотрим вместе.
В общем, следите за обновлениями, скоро посты начнут выходить чаще. В ближайшее время я также планирую наконец-таки сделать подписку на новые статьи, так что следить за новыми статьями станет проще.
Корзина для интернет-магазина на фронте или Пишем модульный javascript
Идея приложения и схема работы.
Итак, интернет-магазин на фронте. Что мы хотим от него? Хотим, чтобы была возможность как минимум вывести каталог товаров, реализовать добавление их в корзину, просматривать оную корзину, менять количество товаров в ней и удалять ошибочно добавленные с пересчетом стоимости заказа. Плюс добавим хранение данных в localStorage, дабы после перезагрузки страницы наша корзина не ушла в небытие.
Функционал подробнее.
Можно посмотреть, что у нас в итоге получится, здесь. Попробуйте добавить товары в корзину, перейти в нее, менять количество и удалять товары, и увидите, как задумана работа магазина. Или можете сразу скачать исходники по этой ссылке.
Структура файлов
Небольшое отступление: я намеренно не стал вводить лишнюю логику для нашего проекта. Хорошей практикой считается разработка с подходом MVC, разделение кода на модели, контроллеры и представления и разбиение этих частей на отдельные файлы для наглядности. Можно долго спорить на тему правильности применения такого подхода для абсолютно всех проектов, но в нашем конкретном примере мы отойдем от этого постулата и весь код для управления корзиной разместим в одном файле, а уже внутри него логически отделим работу с данными от разметки.
Приступаем к разработке.
Я не буду расписывать подробно каждую строчку кода, это заняло бы слишком много места и времени. В статье рассмотрим основные моменты, а весь код можно посмотреть в исходниках по ссылке выше. Код с подробными комментариями.
Начинаем.
Создаем разметку.
На заметку: соглашения по html и css-коду.
Готовим данные и разметку для каталога
Для начала создадим файл для хранения наших товаров: data/goods.json Как видим, это обычный json-массив с четырьмя нужными нам полями. Теперь переходим к созданию каталога. Но прежде чем приступить к написанию js-кода, нам придется написать еще немного разметки для отображения отдельного товара. Мы будем использовать шаблоны html-кода библиотеки underscore для динамической генерации отдельных товаров. Если Вы не знакомы с шаблонами underscore, то у меня есть статья на эту тему. Я же не буду зацикливаться на этом, а просто приведу код шаблона, тем более, что он достаточно тривиален и не требует долгих разбирательств: Что происходит в этом коде? underscore-шаблон представляет собой обычную строку, в которую подставляются нужные данные. Это неплохой способ отделить логику и данные от представления. Вся идея шаблонов в том, что мы не знаем, каким образом получены данные, но мы знаем, как их нужно отобразить. В нашем примере мы даем на вход массив товаров goods (из файла goods.json), перебираем все товары в цикле с помощью функции each библиотеки underscore и для каждого товара выводим свою разметку, подставляя в нужные места id товара, название, картинку и цену. Обратите внимание на дата-атрибуты у кнопки «Добавить в корзину», они будут использованы в дальнейшем. Приведенный код мы поместим в тело body файла index.html. Дальше мы увидим, как связать данные и наш underscore-шаблон.
Пишем js-модуль каталога
Код файла catalog.js будет очень коротким Здесь с помощью замыкания мы объявляем переменную-модуль catalog, пишем функцию init, которая вызывает самую интересную нам функцию _render и экспортируем init наружу, разрешая при этом вызывать catalog.init() из других модулей приложения. На самом деле можно обойтись и без лишней init-функции, но лучше всегда объявлять публичную функцию инициализации во всех модулях для единообразия. При этом функция _render начинается со знака _, чем мы показываем, что эта функция частная и не должна выходить за пределы модуля. Применяя такой подход, мы уже в коде модуля видим, что используется в других модулях, а что предназначено только для внутреннего пользования. Этакая инкапсуляция кода, как в ООП.
Модуль корзины
Вероятно, Вы обратили внимание, что я экспортирую наружу не только init, но и все функции, касающиеся обработки данных. Сделано это для того, чтобы облегчить тестирование кода. Каким образом проходят тесты? Есть 2 способа: ручной и unit-тесты. При тестировании руками мы в консоли браузера вызываем функции модуля и сразу же видим результат. Например, вызвав cart.add(
UPDATED: Для интересующихся unit-тестированием опубликована статья unit-тесты на фронте или изучаем jasmine.js. В ней рассказывается, как тестировать код на примере нашей корзины с помощью популярной библиотеки jasmine.js.
Пишем функции обработки данных
Полный код работы с данными
Из интересного отмечу, что каждая функция возвращает какие-то данные: корзину целиком, добавленный товар или общую сумму. Не все возвращаемые данные используются в модуле, но все облегчают тестирование. Также видим, что в localStorage мы храним сериализованный массив товаров. В функции добавление предусмотрено условие: если мы добавляем товар, уже находящийся в корзине, то не создается дубликат товара, а увеличивается количество уже существующего. При уменьшении количества конкретного товара до нуля, оный удаляется из корзины.
Инициализация настроек. Настройки по умолчанию.
Прежде чем писать функции рендеринга и обработчиков событий, вернемся чуть назад и рассмотрим инициализацию настроек модуля. Функция _initOptions скопирует в переменную opts все настройки, переданные в модуль корзины при его создании. Сначала мы объявляем настройки по умолчанию, а затем «склеиваем» их с данными, пришедшими извне. Для небольшого приложения, как у нас, реализовывать возможность настройки модуля было не обязательно. Но это небольшое увеличение кода дает нам большую гибкость при переносе этого модуля в другой проект.
Рендер корзины и html-шаблон
Для начала создадим шаблон для отображения корзины и поместим его в секцию body файла cart.html. Здесь все знакомо по аналогичному фунционалу в каталоге. В дата-атрибуты помещаем id товаров, чтобы было понятно, с какими именно мы сейчас работаем. Атрибут data-delta показывает, увеличивать или уменьшать количество товара при клике на эту кнопку.
Функции рендеринга.
Обработчики событий.
Приближаемся к завершению.
Всего у нас будет 4 обработчика-клика: добавление в корзину, изменение количества, удаление и оформление заказа. Смотрим:
Собираем модуль корзины в одно целое
Основной код уже написан, нам осталось только написать функцию инициализации корзины и привязки обработчиков событий. Пойдем от обратного, обработчики: Думаю, здесь без особых пояснений, собираем в кучу написанные ранее функции. Иницилизация: Почему мы ввели отдельные настройки renderCartOnInit и opts.renderMenuCartOnInit? Просто потому, что на странице каталога нам нужно инициализировать корзину (мы выводим количество добавленных товаров в меню), но не нужно ее рендерить. Чтобы не усложнять логику лишними проверками, мы разделили эти опции.
Полный код корзины
Главный модуль приложения
Подводим итоги.
Итак, мы написали небольшое приложение простого интернет-магазина с каталогом и корзиной.
UPDATED: В связи с большой популярностью этой статьи и интересу к теме интернет-магазинов в целом запилена и опубликована статья-продолжение Реализация оформления заказа в интернет-магазине на клиенте и сервере. В ней рассмотрен полный цикл по сбору данных о клиенте, размещении формы заказа, отправки ajax-запроса на сервер, создание таблиц в базе данных и добавление этих самых данных, а также отправка писем с заказом. Как обычно, все с примерами. Исходники обновлены. Отправка заказа интегрирована с каталогом и корзиной, рассмотренными в этой статье. Это выглядит как цельное приложение, готовое к работе.
Еще одно обновление: готова статья про добавление способа доставки в интернет-магазин. Читайте здесь
UPDATED 2: Для тех, кому интересно, как сделать дерево с вложенными категориями для своего интернет-магазина, опубликована статья Строим дерево категорий на js, php и mysql. Там описывается интересная библиотека jstree и как достаточно просто сообразить каталог и на клиенте, и на сервере.
UPDATED 3: Для продолжающих интересоваться интернет-магазинами, начинается серия уроков на тему фильтров и сортировок в каталоге товаров. Точка входа здесь.
UPDATED 4: Еще новости по развитию магазина.
Новая статья Сравнение товаров в интернет-магазине.
Хотя главной целью была демонстрация модульного подхода при разработке на javascript и отделении логики от представления, все же модуль корзины получился вполне себе самодостаточным и независимым. При желании мы можем включать его в другие проекты. У нас есть только 2 зависимости модуля: jquery и underscore. Хотя полагаю, что люди, знакомые с обеими библиотеками, добавляют их практически в любой свой проект.
Многие моменты в нашем приложении достаточно спорны. Нет жесткого разделения логики и представления, эти функции объединены в один модуль. Также шаблоны underscore вшиты прямо в код страницы, что тоже не самая хорошая практика, нужно выносить их в отдельные файлы. Я намеренно не стал слишком усложнять структуру. В статье я рассмотрел пример создания кода с одной стороны достаточно модульного, чтобы его можно было удобно протестировать, поддерживать в дальнейшем или извлечь какие-то идеи для своих будущих приложений, но с другой стороны не настолько сложного, чтобы в нем нужно было слишком долго разбираться. В конце концов для серьезной javascript-разработки создаются библиотеки и фреймворки, и рано или поздно мы все приходим к пониманию, что их нужно знать и изучать. Backbone, Angular, Ember, React, существует их очень много и постоянно появляются новые. И чем больше мы будем изучать и узнавать различные подходы, тем шире будет наш кругозор и больше возможностей выбора.
Урок 52. Шаблон каталога товаров
Сергей 05.08.2014 13136 3.9 из 5.0 (15)
Цель урока
Создать страницы каталога товаров интернет магазина. Ознакомиться с популярными блоками. Провести базовую внутреннюю поисковую оптимизацию.
Урок будет полезен не только тем, кто только создает магазин, но и владельцам существующих магазинов.
Основная цель
В зависимости от продаваемых товаров, цели могут меняться.
Исходя из этого, можно сформировать список вопросов посетителя, на которые потребуется ответить:
Вопросы
В Яндекс.Метрике это можно отследить по карте ссылок на страницах категорий:
Если переходов нет, то смотрим карту путей по сайту, чтобы узнать, куда уходят посетители со страниц каталога. Скорее всего это будет страница поиска.
Задачи
Для страницы каталога существует ряд задач, выполнение которых поможет повлиять на итоговую величину конверсии:
Задача | Решение |
---|---|
Создайте очевидный каталог |