Админка магазина на vue.js. Урок 1. Список товаров

декабрь 16 , 2018
Следующая статья Демо Исходники

С админкой на файлах мы закончили, пора переходить к вещам посерьезнее. На очереди админка для интернет-магазина, уже на базах данных, все как положено. За магазином далеко ходить не нужно, возьмем наш shop.webdevkin.ru. Будет здорово, если Вы с ним уже знакомы. Если нет, то посмотрите статью Структура базы данных в интернет-магазине, для админки этого хватит. К тому же по ходу уроков я буду стараться пояснять неочевидные моменты и давать ссылки на нужные места магазина. Постараемся не заблудиться :-)

В админке на файлах мы сделали минимальный набор функций: список редактируемых параметров и все. Но интернет-магазин дело посложнее. Мы хотим уметь работать с товарами, категориями, ценами и брендами. Поэтому одной статьей не обойдемся, будет серия уроков. Уроки небольшие, чтобы освоить материал за один раз и при этом не скучать.

Важный момент: админку будем писать на Vue.js. Почему? До этого клиентский код мы писали на смеси javascript + jquery. Но во-первых, одно и то же делать скучно. Во-вторых, админка - проект сложнее, чем внешняя часть магазина, например, корзина или даже фильтры. Поэтому лучше писать на специальных фреймворках или библиотеках. В-третьих, новые знания всегда пригодятся.

Почему vue? Мне не нравится ангуляр. Он выглядит чересчур сложным и местами заумным, а я за простые решения. На реакте пишут многие, и в интернетах по нему до фига туториалов. Я не гнушаюсь и бекбоном, но 2018 год, рассказыть о нем будет странно. В общем, из всего этого разнообразия мне больше нравится vue. У него похожий на реакт подход (только проще, на мой взгляд), отличная документация, растет популярность и звездочки на гитхабе. Насчет документации убедился сам: чтобы начать эту админку, мне хватило полдня для изучения основ vue. Чтобы понять код из уроков, Вам будет достаточно пробежать глазами раздел Основы. Попробуйте.

Еще важный момент: vue я только начал изучать. Поэтому пробовать, ошибаться и учиться дальше будем вместе. Начнем с самого простого, потом постепенно усложним, попробуем разделить приложение на компоненты, изучим взаимодействие с сервером, потрогаем vuex и роутинг. Только все это не на todo-списках, а на интернет-магазине. Если Вы знаете vue, круто, если будете делиться хорошими идеями и замечаниями в комментах.

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

Давайте определимся, что хотим от первого урока. Предлагаю подключить vue и вывести список товаров. Серверной части сегодня не будет, воспользуемся тем, что мы делали в фильтрах для интернет-магазина. https://shop.webdevkin.ru/scripts/catalog.php - этот запрос вернет список товаров. Откройте в браузере и убедитесь, что запрос работает. Возвращает объект { code: 'success', data: { goods: [/* массив товаров */] }} Чтобы начать разрабатывать локально, скачайте исходники магазина и накатите sql-миграции. Саму админку будем делать в папке admin.


Заготовка проекта и html-код.

Создадим в папке admin 3 файла: index.html, app.js и style.css. В index.html подключим два css файла: https://cdnjs.cloudflare.com/ajax/libs/mini.css/3.0.1/mini-default.css и ./style.css. Это еще одно нововведение: верстать будем с помощью библиотечки mini.css. На бутстрапе у нас сделан сам магазин да и много других примеров, давайте попробуем что-то другое.

Теперь скрипты. Подключаем в конце index.html 3 скрипта: https://cdn.jsdelivr.net/npm/vue/dist/vue.js, https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js и ./app.js. Сам vue, axios - библиотека для ajax-запросов и наш собственный файлик.

Пора написать первый код в index.html.

    
Каталог

Список товаров

Здесь мы видим обычную верстку. id="app" корневому контейнеру задаем, потому что vue хочет знать, откуда начинаются ее полномочия. header и footer с гордыми логотипом "Webdevkin". И сетка с заголовком страницы h1 и пока что комментом "Список товаров" вместо реальных данных. Про сетку, header и footer можно почитать в документации mini.css.

Пока что ничего нового. Новое будет в следующем коде на месте списка товаров

    
Id Название Бренд Цена Рейтинг

Обычная таблица с необычными параметрами в tr. Расскажу по очереди.

is="ProductItem" означает, что за одну запись в таблице формирует компонент ProductItem. Его напишем в app.js, потерпите.
v-for="product in products" - это цикл. У нас есть некая переменная products, хранящая список всех товаров. Мы перебираем все товары и выдергиваем их по одному в переменную product.
Следующая же строка :product="product" говорит, что эта переменная передается в компонент ProductItem под именем product. Чтобы понять, где какой "product", можно эти строчки переписать так

    v-for="item in filteredProducts"
    :product="item"
    :key="item.good_id"

Последняя :key="product.good_id" пока нам не понадобится, но документация vue рекомендует всегда передавать параметр key из цикла в компонент. Зачем-то это надо, придет время, выясним.

С html закончили. Сначала непривычно, что в разметку добавляются такие странные атрибуты. Но постепенно мы будем понимать, что это удобно. Глядя на хтмл, уже можно представить, какой код нас ждет в javascript. Давайте его напишем.


app.js - javascript-основа приложения

Заготовка выглядит так

    // Экземпляр vue
    var app = new Vue({
        el: '#app',
        data: {
            products: []
        },
        mounted: function() {
            var that = this;
            axios
                .get('/scripts/catalog.php')
                .then(function(response) {
                    that.products = response.data.data.goods;
                });
        }
    });

new Vue({ ... }) - это создание экземпляра vue. Дальше вся сила в параметрах.
el: '#app' показывает, где находится корневой элемент для vue.
В объекте data храним все данные, доступные в приложении. products - массив товаров, по умолчанию пустой.
mounted - это функция, которая срабатывает после монтирования экземпляра vue.
В mounted нам нужно получить товары с сервера, делаем это с помощью axios. Методом get дергаем /scripts/catalog.php и в колбеке then копируем в products полученный с сервера массив.
response.data.data.goods - 2 раза data, почему? В объекте response от axios хранятся не только сами данные от сервака, но еще http-код ответа, статус и некоторые другие вещи. А в data собственно данные. А второй data - это мы следуем по цепочке объекта, вернувшегося с сервера. Напоминаю, ответ с сервера смотрите здесь - https://shop.webdevkin.ru/scripts/catalog.php
Дополнительных параметров вроде content-type указывать не нужно - axios сам понимает, если вернулся json, то сразу его и парсит.

Теперь нам нужно создать компонент ProductItem, который отвечает за один товар. Напишем в начало app.js такой код

    // Компонент продукта
    Vue.component('ProductItem', {
        props: ['product'],
        template: `
        
            {{ product.good_id }}
            {{ product.good }}
            {{ product.brand }}
            {{ product.price }}
            {{ product.rating }}
        
        `
    });

Здесь мы создаем компонент с таким-то названием и таким-то шаблоном. В массиве props перечисляем все свойства, которые передаются в компонент из родительского. Помните, оттуда, где мы в html писали v-for="product in products" и :product="product". А шаблон это обычная строка с плейсхолдерами. Они указываются в двойных фигурных скобках.

Вот теперь можно обновить страницу и посмотреть на получившуюся таблицу.

Немного удиляет дефолтная таблица mini.css, которая по умолчанию 400px высотой. Мне это не понравилось, поэтому перезатер нужные стили в файле style.css

    table:not(.horizontal) {
        max-height: 1000px;
    }

Вот так у нас получилось. Я бы на этом закончил статью, но не удержусь и продемонстрирую, как реализовать простой поиск товаров. На чистом js или jquery нам пришлось бы сохранять где-то данные, навешивать события на изменения инпута поиска и перерисовывать таблицу. На vue происходит то же самое, только многое без нашего участия.


Поиск по названию товара.

Добавим в index.html перед таблицей поле поиска

    

v-model означает, что в приложении помимо массива products появляется еще один параметр inputSearch. Модификатор .trim будет обрезать пробелы с обеих сторон инпута.

И еще одно. Заменим строку

    v-for="product in products" на v-for="product in filteredProducts".

filteredProducts - это еще одно поле, которое будет отдавать массив товаров с учетом поля поиска.

Переходим в app.js. Сначала в объект data добавим новое поле inputSearch: ''. А затем после data напишем еще один блок

    computed: {
        filteredProducts: function() {
            var that = this;
            return this.products.filter(function(product) {
                return product.good.toLowerCase().indexOf(that.inputSearch.toLowerCase()) !== -1;
            });
        }
    }

Что такое объект computed? В нем хранятся вычисляемые поля - это такие, значения которых зависят от других полей. Наш filteredProducts зависит от product и inputSearch одновременно. В filteredProducts возвращаем массив, отфильтрованный по принципу совпадения инпута с названиями товаров. К нижнему регистру приводим для удобства, чтобы не заставлять себя в нужные моменты нажимать shift.

Весь кайф вычисляемых полей в том, что не нужно думать, когда меняется inputSearch или products - при их изменении зависимые поля вычислятся сами. Или точнее при обращении к ним вызывается функция, которая рассчитывает новое значение. Но не суть, это не так важно. Важно то, что больше ничего для поиска делать не нужно. Навешивание событий, их прослушка и рендер таблицы - все это делает vue за нас. Мы же больше сосредотачиваемся на логике приложения, а не на всяких скучных вещах.

На этом первый урок по админке на vue закончен. Демо смотрите по этой ссылке, а здесь можно скачать исходники.

Скоро будут новые уроки. До встречи!

Что еще почитать по теме

Следующая статья Демо Исходники
Как Вам статья? Оцените!
Понравилась статья? Поделись с другими!
Подписка на новые статьи
Подписаться