[Перевод] Веб-приложение на 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
, которое используется для указания того, активна плавающая кнопка или нет.
Итоги
Сегодня мы внесли некоторые улучшения в компоненты, переработали их с прицелом на повторное использование кода, добавили функционал вывода списка клиентов. Полный вариант приложения, как обычно, можно найти в репозитории проекта.
В следующем материале мы продолжим работу над приложением, и, вероятнее всего, её завершим.
Уважаемые читатели! Стремитесь ли вы к возможности повторного использования кода при работе над своими проектами?