Интернет-магазин на vue.js + nuxt.js + apisful
Сегодня мы соберем не очень сложный, но очень перспективный интернет-магазин. Требований к нему ни много, ни мало:
- посетители смогут фильтровать товары по категории
- будут загружать только изображения, подходящие размеру и плотности их экрана
- будут добавлять товары в корзину и оформлять заказы
- мы будем получать email-уведомления о новых заказах
Большие туториалы с кучей кода никто не читает, поэтому все исходники лежат на github, а в этой статье мы их комментируем, объясняя потенциально непонятные моменты.
Все используемые в этом материале сервисы бесплатны.
Исходники здесь Живое демо тутДанные и бэкенд
В рамках туториала, вероятно, было бы достаточно сложить объекты товаров в массив, но мы сразу хотим сделать так, чтобы этим всем можно было пользоваться при создании реального магазина. REST API и интерфейс администрирования для нас сгенерирует Apisful - там буквально пара кликов, магия и все готово.
- Создаем аккаунт здесь или авторизуемся тут.
- Жмем create new project
- Вводим название проекта и обязательно выбираем шаблон
E-Commerce
- тогда все создастся само и нам не придется делать лишних кликов. - Жмем save
Как результат имеем следующие коллекции (это как таблицы в базе данных):
- Categories - туда добавляем категории товаров, которые у нас будут появляться: штаны, маски для дайвинга и вот это вот все.
- Products - это базовый товар: футболка c v-образным вырезом, например.
- Product Variants - это вариации базового товара. Например, футболка c v-образным вырезом оливкового цвета.
Суть Products и Product Variants в том, что все футболки c v-образным вырезом стоят одинаково и находятся в одной категории, но футболки фиолетового цвета остались только в размере S и М, тогда как оливковые есть во всех размерах - характеристики размера мы выносим в Product Variants. Это позволит нам изменять список доступных размеров при выборе цвета футболки на сайте. Вот так:
На этом бэкенд пока откладываем и движемся дальше
Vue.js + Nuxt.js
Создаем проект
Сам по себе vue.js хоть и очень классный, но занимается только одной конкретной проблемой - слоем отображения. Нам же нужно еще:
- обрабатывать переходы на страницы - в этом нам поможет vue router
- писать веб компоненты - для этого есть vue loader
- иметь локальный сервис, в который смогут вносить изменения все компоненты сайта (для создания корзины заказа) - vuex знает в этом толк
Это все отдельные библиотеки, которые нужно собрать вместе в дополнение к vue.js. Собирать сами мы, разумеется, ничего не хотим, поэтому воспользуемся nuxt.js - это фреймворк, который уже собрал все необходимые vue библиотеки вместе и позволит нам просто взять и начать кодить.
Создать nuxt.js проект невероятно просто
yarn create nuxt-app <project-name>
# или
npx create-nuxt-app <project-name>
# или
npm init nuxt-app <project-name>
После вызова одной из команд выше, nuxt.js начнет задавать нам всякие каверзные вопросы (а мы на них ответим):
- как назвать проект (на ваше усмотрение)
- js мы хотим или ts (в этом руководстве используем js)
- какой пакетный менеджер будем использовать (будем yarn)
- какой css фреймворк желаем (никакого нам не надо)
- и какие модули нам установить (только axios)
- как насчет линтера (тут выбирайте на свой вкус)
- тестировать будем? (пока нет)
- какую сборку собирать (Single Page App)
- как будем деплоить (Static/JAMStack hosting)
После этой непродолжительной беседы, nuxt.js сделает выводы и как результат у нас появится папка с проектом. Вот так она выглядит

Там есть все, что нам необходимо и по ходу туториала многим мы воспользуемся. Остается только один момент: мы пишем стили на sass, а значит нужно установить пакеты, которые этот самый sass будут компилировать в css (автоматически, конечно):
yarn add --dev node-sass sass-loader
Страницы и компоненты
Все страницы находятся в директории pages
. Стоит создать в папке pages
файл с расширением .vue
и nuxt.js сразу же
сгенерирует для него соответствующий route. О роутах подробнее можно почитать здесь.
Файл pages/index.vue
является главной страницей сайта.
Файл pages/categories/_category.vue
соответствует url в духе /categories/t-shirts-Xmw1kx5
.
Эти две страницы (главная и категории) выглядят одинаково с точки зрения UI, отличается только список товаров. Поэтому
мы создали компонент components/products-list/CommonProductsListPage.vue
, который проделывает всю работу по отображению элементов страницы.
В коде главной страницы и страницы категории мы используем этот компонент, передавая в него функцию выборки товаров.
В компоненты стоит выносить все то, что вы собираетесь переиспользовать или логику чего вы хотите вынести отдельно. Вот такие компоненты есть у нас в этом проекте

Выборка товаров
Apisful автоматически генерирует REST API к нашей схеме данных. То есть если у нас есть коллекция Products
, то сможем получить список всех товаров запросом на url
https://api.apisful.com/v1/collections/products/
Подробнее с Apisful REST API можно ознакомиться здесь.
Для работы с апи мы создали директорию api
. В ней файл api/index.js
с базовыми настройками, а также файлы для работы с каждой коллекцией.
Шаблоны страниц
На примере главной страницы и страницы категории мы показали как можно вынести повторяющиеся элементы интерфейса (или логики) в компонент.
Но как быть с теми элементами страницы, которые повторяются на каждой (или почти каждой) странице?
Можно подключать один и тот же элемент на каждой странице, а можно воспользоваться layouts
.
Layout - это шаблон страницы, в который встраивается ее содержимое. В нашем случае в layout/default.vue
находится шаблон, который оборачивает всю страницу в
<div class="container">
и содержит шапку сайта (логотип и ссылку на корзину).
Шаблонов может быть больше одного. Дефолтный шаблон применяется ко всем страницам автоматически. Если странице нужен другой шаблон - например layouts/blog.vue
, то в компоненте это нужно указать вот так
<script>
export default {
layout: 'blog'
}
</script>
Vuex на примере корзины
Нередко бывает так, что на клиенте нам необходимо централизированное хранилище, к которому можно получить доступ из любого компонента.
В нашем случае мы используем такое хранилище для работы с корзиной:
Из pages/products/_product.vue
мы добавляем товар в корзину.
В components/cart/CartProductsList.vue
выводим список товаров и позволяем изменять количество.
А в components/CommonNavbar.vue
показываем сколько товаров в корзине.
Логика работы такого хранилища находится в store/cart.js
и использует Vuex.
Vuex парой абзацев объяснить трудно, имеет смысл зайти на сайт и прям вникнуть.
Если вам кажется, что все слишком сложно и можно жить без vuex, то, скорее всего, так и есть и пока изучение vuex можно отложить.
Плагины
Плагины позволяют расширить функциональность nuxt.js. Используя плагины можно подключать как сторонние библиотеки, так и небольшие кусочки своего кода.
Мы, например, создали файл plugins/filters.js
, в котором объявили глобальный фильтр, форматирующий цену.
Чтобы он заработал, нужно в файле nuxt.config.js
найти массив plugins
и дописать в него путь к плагину. Вот так

О фильтрах во vue.js можно почитать тут, а о nuxt.js плагинах здесь.
Assets и static
Эти две папки предназначены для статических файлов: изображения, иконки, стили...
Разница между ними в том, что содержимое assets
пройдет через webpack - минифицируется, изменит название и претерпит другие модификации.
Поэтому к таким файлам нужно обращаться через ~/assets/path/to/file
, на этапе компиляции такие пути заменятся на нужные.
Эту папку мы используем практически для всей статики.
Все то, что находится в static
без изменений перенесется в корневую директорию сайта при сборке.
Это хорошо для таких файлов как favicon.ico
, robots.txt
и тому подобных.
Уведомления о новых заказах
Когда пользователь нажимает кнопку "Place an order", мы сохраняем заказ в коллекции Orders
. Как мы это делаем можно увидеть в файле api/order.js
.
Сами заказы можно увидеть в админке, вот:

Для того, чтобы получать уведомления о новых заказах, мы воспользуемся тригерами. Создать тригер проще простого:
- В меню слева в разделе
Triggers
нажмем Add new - Введем название тригера - New order (или любое другое)
- И настроим логику тригера - Send
email notification
whennew record added
in collectionOrders
- Жмем Save
Теперь каждый раз, когда в коллекции Orders появляется новая запись, мы будем получать уведомление на почту.
Заключение
Теперь мы, я надеюсь, понимаем как пользоваться nuxt'ом, зачем он нужен, как бесплатно и в пару кликов получить бэкенд для своего проекта.
Подписывайтесь и вы не пропустите следующие умопомрачительные туториалы.