Админка магазина на vue.js. Урок 5. Разбиваем приложение на компоненты

февраль 14 , 2019
Метки:
Предыдущая статья Следующая статья Исходники

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

В этом уроке мы разобьем приложение на несколько компонентов поменьше. Также добавим две новые страницы и узнаем, как переключаться между ними.

Начнем с самого простого.


Выделяем шапку и подвал в компоненты.

В app.js создадим 2 новых компонента по аналогии с ProductItem. Они очень простые и содержат только верстку.

    
    // Компонент шапки
    Vue.component('Header', {
        template: `
            
Каталог
` }); // Компонент подвала Vue.component('Footer', { template: ` ` });

Мы просто перенесли верстку шапки и подвала из index.html в поле template соответствующих компонентов. Теперь подключим их в index.html

Вместо

    
    
Каталог

напишем

    
    

То же самое с подвалом. Вместо

    
    

пишем

    
    

Все, оба блока вынесены. Переходим к следующему.


Компонент Products

Сейчас весь код работы с фильтрами, вычисляемыми полями и методами написан в new Vue. Давайте создадим новый экземпляр vue вот так

    
    // Экземпляр vue
    var app = new Vue({
        el: '#app'
    });

Это все, остальная логика уйдет в новый компонент Products. Найдем старое объявление vue

Здесь менять много не придется. Посмотрим на начало кода

    
    // Экземпляр vue (старый)
    var app = new Vue({
        el: '#app',
        data: {
        // и так далее...

Заменим строку

    
    var app = new Vue({

на

    
    Vue.component('Products', {

Затем удалим el: '#app' - в компоненте оно не нужно. И сделаем поле data не объектом, а функцией, которая возвращает объект - это требование vue.js при создании компонентов.

Получится вот так

    
    data: function() {
        return {
            products: [],
            categories: [],
            brands: [],
            sortRules: [
                { key :'id:asc', title: 'По порядку' },
                { key :'rating:desc', title: 'По рейтингу' },
                { key :'price:asc', title: 'По цене, сначала дешевые' },
                { key :'price:desc', title: 'По цене, сначала дорогие' }
            ],
            inputSearch: '',
            selectCategory: 0,
            selectBrand: 0,
            minPrice: 0,
            maxPrice: 0,
            selectSort: 'id:asc'
        }
    }

Все, с логикой компонента Products закончили. А точнее, мы ее и не меняли, а целиком взяли ранее написанную. Осталось не забыть скопировать верстку в поле template нового шаблона

    
    template: `
        

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

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

И удалить эту верстку из index.html. То есть вместо большой портянки html у нас будет краткое подключение компонента

    
    

И вся верстка index.html будет выглядеть гораздо лаконичнее

    
    

Прежде чем пойти дальше, поясню насчет компонента Products. Вы заметили, что он получился сложным и громоздким. Было бы неплохо разделить его как минимум на фильтры и таблицу товаров. Я совершенно согласен и мы это сделаем, но чуть позже, в следующих уроках.

Мы можем разделить Products и сейчас. Но несмотря на небольшой размер приложения многие наши данные взаимосвязаны. Будет много мороки с перекидыванием продуктов, брендов, категорий и фильтров из дочерних компонентов в родительские и наоборот. В будущем мы от этого не избавимся, но сможем сделать проще, когда будем работать с однофайловыми компонентами .vue и разберемся с vuex. Поэтому пока оставим громоздкий Products в таком виде и запишем в планы его отрефакторить. Уже в следующем уроке мы сделаем первые шаги по улучшению.

Переходим к следующей теме.


Добавляем новые вкладки-страницы

Давайте сделаем отдельные страницы для категорий и брендов.

Мы уже умеем создавать компоненты и новые страницы сразу сделаем по уму. Создадим компонент на каждую вкладку-страницу

    
    // Компонент вкладка категории
    Vue.component('Categories', {
        template: `
            

Категории

` }); // Компонент вкладка бренды Vue.component('Brands', { template: `

Бренды

` });

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

Для начала заведем список всех страниц приложения. В нашем случае это будут вкладки или табы. Добавим в создании экземпляра vue поле data

    
    // Экземпляр vue
    var app = new Vue({
        el: '#app',
        data: {
            currentTab: 'Products',
            tabs: [{
                component: 'Products',
                title: 'Товары'
            }, {
                component: 'Categories',
                title: 'Категории'
            }, {
                component: 'Brands',
                title: 'Бренды'
            }]
        }
    });

Массив data.tabs содержит компонент vue и заголовок вкладки, который нужно вывести в меню. currentTab - текущая вкладка, по умолчанию Products.

Выведем в меню шапки все вкладки. Для этого в index.html в компонент Header передадим свойство tabs.

    
    

Теперь перейдем в app.js в сам компонент Header и добавим в props свойство tabs. А вместо кнопки-ссылки

    
    Каталог

выведем список кнопок через полученный массив tabs

    
    

Полный код будет такой

    
    // Компонент шапки
    Vue.component('Header', {
        props: ['tabs'],
        template: `
            
` });

Если мы обновим страницу, то увидим, что в меню появились три кнопки. Но при клике на них ничего не происходит. Нужно дописать код, который при клике устанавливает нужное значение свойства currentTab и переключает компоненты Products, Categories и Brands.

Основная хитрость здесь в том, что currentTab находится в корневом компоненте, а менять его нужно из дочернего Header. То есть передать данные "наверх". Vue легко позволяет это сделать с помощью $emit. Добавим в Header button событие @click

    
    

Новой строкой с @click и $emit мы говорим: при клике на кнопку отправь родительскому компоненту кастомное событие change-tab и данные tab. change-tab мы придумали сами, а tab - это вкладка, которую мы выбрали при клике.

Теперь в index.html, где мы выводили компонент Header, нужно поймать это событие и что-то сделать с данными из tab. Кастомные события обрабатываются точно так же, как и встроенные click, input и прочие. Изменим код в Header добавлением одной строки

    
    

Здесь мы говорим: когда сработает событие change-tab, нужно запустить метод changeTab. Точно так же, как бы сделали это при клике.

Метод changeTab просто установит поле currentTab в новое значение. Вот так

    
    methods: {
        changeTab: function(tab) {
            this.currentTab = tab.component;
        }
    }

Конечно же, это метод не Header, а корневого экземпляра, там, где и объявлено свойство currentTab.

Остался последний штрих - показывать нужную страницу в зависимости от currentTab. Идем в index.html и ищем строку

    
    

Здесь мы явно указываем компонент Products. Давайте поправим код

    
    

Здесь мы говорим, что компонент для вывода заранее неизвестен и его нужно брать из свойства currentTab. Обратите внимание на is с двоеточием

    
    :is="currentTab"

Header и Footer мы подключаем через просто is, потому что там названия компонентов известны. А здесь нужно брать не строку, а именно значение из currentTab, поэтому добавляем : для связывания.

Вот теперь все, можно переключать вкладки и наблюдать разные страницы.

Напоследок маленькая хитрость. Представим ситуацию, мы активно работаем с товарами, набили кучу фильтров, переключились соседнюю вкладку добавить новый бренд и вернулись обратно. При этом компонент Products отрендерится заново и фильтры сбросятся. Если хотите сохранять состояние фильтров, да и вообще любых данных компонента, то оберните нужный компонент тегом keep-alive

    
    
        
    

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

Исходники приложения можно скачать здесь


Что будет в следующем уроке?

До сих пор мы писали код, который годится для учебного проекта. Но он не годится для серьезной разработки. Почему?

1. Мы разбили приложения на компоненты, но до сих пор держим их в одном файле app.js.
2. У нас нет никакой структуры приложения, только 3 файла: index.html, app.js и style.css.
3. Мы не можем использовать классные фишки vue вроде однофайловых компонентов.
4. Мы никак не упоминали сборку приложения в dev и production-режиме.

Эти недостатки мы исправим в следующем уроке, где будем разбираться с отличным инструментом vue cli

До встречи!

Все уроки админки на vue.js

Предыдущая статья Следующая статья Исходники
Метки:
Заходите в группу в контакте - https://vk.com/webdevkin
Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.
Истории из жизни айти и обсуждение кода.
Как Вам статья? Оцените!