[Перевод] Веб-приложение на Node и Vue, часть 4: повторное использование кода
Перед вами четвёртая часть серии материалов, которые посвящены разработке веб-приложения Budget Manager с использованием Node.js, Vue.js и MongoDB. В первой, второй и третьей частях речь шла о создании основных серверных и клиентских компонентов приложения. Сегодня мы продолжим развитие проекта, а именно — займёмся списками документов и клиентов. Кроме того, нельзя не заметить, что к настоящему моменту сделано уже немало, поэтому вполне можно критически взглянуть на то, что получилось, и поработать над повторным использованием кода.

Совершенствование компонентов
Начнём с изменения имени папки Budget на List. Кроме того, переименуем три компонента, которые находятся в этой папке. А именно, BudgetList теперь будет называться List, BudgetListHeader получит название ListHeader, а BudgetListBody — ListBody. В итоге папка и файлы компонентов должны выглядеть так, как показано на рисунке ниже.

Откроем файл компонента List и приведём его к такому виду:
Тут мы изменили имя класса таким образом, чтобы оно соответствовало имени компонента. Кроме того, мы поменяли имена слотов.
Откроем файл компонента ListHeader и внесём в него следующие изменения:
{{ header }}
Здесь, опять же, мы поменяли имена классов, а так же отредактировали шаблон, настроив его на вывод данных из свойств (props). Так мы сможем повторно использовать этот компонент на других страницах.
Теперь пришёл черёд компонента ListBody:
{{ info }}
visibility
mode_edit
delete_forever
Этот компонент мы тоже подготовили к повторному использованию, задействовав вывод данных из свойств.
Теперь откроем файл компонента Home и отредактируем его:
Focus Budget Manager
{{ message }}
Здесь мы поменяли команды импорта и теги, привели их в соответствие переименованным компонентам, добавили snackbar, что даёт возможность показывать сообщения об ошибках в том случае, если нам не удастся получить данные. Кроме того, мы добавили сюда новый массив для данных компонента, budgetHeaders, а также данные, необходимые для snackbar.
Мы будем использовать budgetHearders для показа заголовков списка. Кроме того, мы внесли некоторые изменения в метод getAllBudgets:
getAllBudgets () {
Axios.get(`${BudgetManagerAPI}/api/v1/budget`, {
headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },
params: { user_id: this.$cookie.get('user_id') }
}).then(({data}) => {
this.budgets = this.dataParser(data, '_id', 'client', 'title', 'state')
}).catch(error => {
this.snackbar = true
this.message = error.message
})
},
Теперь, вместо того, чтобы передавать данные документов напрямую, мы используем новый метод:
dataParser (targetedArray, ...options) {
let parsedData = []
targetedArray.forEach(item => {
let parsedItem = {}
options.forEach(option => (parsedItem[option] = item[option]))
parsedData.push(parsedItem)
})
return parsedData
}
Этот метод, в качестве первого аргумента, принимает массив и произвольное число аргументов, которые сформируют массив options с использованием оператора расширения.
Метод будет брать каждый элемент из массива, в данном случае это — документы, и создавать новый объект parsedItem.
Этот объект будет содержать данные массива options, после завершения его подготовки он будет помещён в массив parsedData, который мы возвращаем из этого метода.
И, наконец, мы перехватываем ошибки (если таковые возникнут), активируя snackbar.
Теперь нужно отредактировать код маршрутизатора, для этого перейдём в папку router и откроем index.js:
import Vue from 'vue'
import Router from 'vue-router'
import * as Auth from '@/components/pages/Authentication'
// Pages
import Home from '@/components/pages/Home'
import Authentication from '@/components/pages/Authentication/Authentication'
// Global components
import Header from '@/components/Header'
import List from '@/components/List/List'
// Register components
Vue.component('app-header', Header)
Vue.component('list', List)
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'Home',
components: {
default: Home,
header: Header,
list: List
}
},
{
path: '/login',
name: 'Authentication',
component: Authentication
}
]
})
router.beforeEach((to, from, next) => {
if (to.path !== '/login') {
if (Auth.default.user.authenticated) {
next()
} else {
router.push('/login')
}
} else {
next()
}
})
export default router
Тут мы поправили команды импорта, имена компонентов, теги и пути, а также сделали некоторые улучшения в router.beforeEach, так как мы собираемся защищать любой маршрут, отличающийся от login, мы убираем meta из маршрута страницы Home.
Вывод информации о клиентах
Вместо того, чтобы создавать новую страницу, предназначенную для вывода списка клиентов, мы будем использовать уже существующую страницу Home. Поэтому вернёмся к компоненту Home и создадим новый массив в данных компонента, дав ему имя clients, а также создадим массив clientHeaders и логическую переменную budgetsVisible:
return {
budgets: [],
clients: [],
budgetHeaders: ['Client', 'Title', 'Status', 'Actions'],
clientHeaders: ['Client', 'Email', 'Phone', 'Actions'],
budgetsVisible: true,
snackbar: false,
timeout: 6000,
message: ''
}
Теперь добавим новый метод:
getAllClients () {
Axios.get(`${BudgetManagerAPI}/api/v1/client`, {
headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },
params: { user_id: this.$cookie.get('user_id') }
}).then(({data}) => {
this.clients = this.dataParser(data, '_id', 'client', 'email', 'phone')
}).catch(error => {
this.snackbar = true
this.message = error.message
})
},
Вызовем этот метод при монтировании компонента:
mounted () {
this.getAllBudgets()
this.getAllClients()
},
Как теперь вывести сведения о клиентах? Очень просто. Достаточно внести ещё некоторые изменения в компонент Home:
Focus Budget Manager
{{ message }}
Теперь мы передаём переменную budgetVisible в Header и, кроме того, используем эту переменную в тернарном операторе сравнения для вывода нужных данных. В Header так же попадает переменная toggleVisibleData, где мы инвертируем значение budgetsVisible. Причина, по которой мы передаём в Header свойства, заключается в том, что благодаря такому подходу мы можем сделать ещё некоторые улучшения, о которых поговорим ниже. Кроме того, в слотах list-header и list-body мы используем тернарные операторы сравнения.
Итак, теперь внесём улучшения в Header:
{{ budgetsVisible ? "Clients" : "Budgets" }}
Sign out
Теперь цвет заголовка будет зависеть от состояния переменной budgetsVisible. Если документы видимы, заголовок будет иметь светло-синий цвет, если нет — зелёный.
Кроме того, цвет и надпись на кнопке будут меняться в зависимости от значения budgetVisible, по её щелчку вызывается обработчик соответствующего события, меняющий состояние логической переменной.
Кроме того, мы внесли некоторые изменения в scss.
И, наконец, займёмся компонентом ListBody:
{{ info }}
visibility
mode_edit
delete_forever
Изменения, внесённые сюда, похожи на те, что мы выполнили в коде компонента Header.
Промежуточные результаты
Вот как теперь выглядит список документов:

А вот — список клиентов:

Теперь, когда мы можем видеть списки зарегистрированных документов и клиентов, создадим плавающую кнопку (Floating Action Button, FAB), которая будет содержать кнопки, позволяющие работать со списком. Всё ещё находясь в коде компонента Home, добавим следующий код ниже v-snackbar:
add
close
assignment
Add new Budget
account_circle
Add new Client
В FAB содержится три кнопки. Первая действует как активатор для FAB, вторая служит для добавления документов, третья — для добавления клиентов. Добавим теперь новое логическое значение для FAB в данные компонента Home:
data () {
return {
budgets: [],
clients: [],
budgetHeaders: ['Client', 'Title', 'Status', 'Actions'],
clientHeaders: ['Client', 'Email', 'Phone', 'Actions'],
budgetsVisible: true,
snackbar: false,
timeout: 6000,
message: '',
fab: false
}
},
Здесь мы добавили логическое значение fab, которое используется для указания того, активна плавающая кнопка или нет.
Итоги
Сегодня мы внесли некоторые улучшения в компоненты, переработали их с прицелом на повторное использование кода, добавили функционал вывода списка клиентов. Полный вариант приложения, как обычно, можно найти в репозитории проекта.
В следующем материале мы продолжим работу над приложением, и, вероятнее всего, её завершим.
Уважаемые читатели! Стремитесь ли вы к возможности повторного использования кода при работе над своими проектами?
