В этом посте я расскажу, как сделать компонент для калькулятора расчета стоимости.
Постановка задачи такая:
✔️ В калькулятор необходимо добавлять неограниченное количество комнат и указывать их длину и ширину (предполагается, что они прямоугольные).
✔️ Калькулятор должен моментально вычислять стоимость ремонта, исходя из оценки: 50 тыс. рублей на 1 кв. метр.
В качестве фремворка будем использовать VueJS 3 версии.
Сначала создадим демонстрационный проект для тестирования нашего компонента.
Для этого нужно будет установить среду для сборки NodeJS c официального сайта: https://nodejs.org/ru
Также будем использовать IDE VSCode, ее тоже можно скачать бесплатно с официального сайта: https://code.visualstudio.com
Создаем новую папку для проектов открываем ее в vscode и запускаем в нем терминал.
Все эти шаги описаны подробно в нашей предыдущей статье:
1 ЭТАП
В терминале вбиваем команду для создания нового проекта vuejs (попутно он предложит установить утилиту vue-create, а потом предложит указать название проекта и другие опции - там пока можно везде выбрать No):
```sh
npm create vue@latest
```
Переходим в терминале в папку проекта:
```sh
cd название проекта
```
Устанавливаем локально зависимости:
```sh
npm i
```
Далее для локального запуска проекта нужно будет вбить в терминал:
```sh
npm run dev
```
Запустится локальный стенд и будет указана ссылка, по которой можно посмотреть результат в браузере.
Первым делом создадим компонент Calc.vue в папке /src/components/ со следующим содержимым:
```js
// Calc.vue
<script setup>
</script>
<template>
<input type="button" value="+ Добавить комнату">
<table>
<tr>
<th>Комната:</th>
<th><input type="text"></th>
</tr>
<tr>
<td>Длина</td>
<td><input type="number"> м.</td>
</tr>
<tr>
<td>Ширина</td>
<td><input type="number"> м.</td>
</tr>
<tr>
<td></td>
<td><input type="button" value="удалить комнату"></td>
</tr>
</table>
<div>
Итог: 100 000 руб
</div>
</template>
```
Это будет прототип будущего калькулятора.
Добавим копонент в главный файл App.vue:
```js
// App.vue
<script setup lang="ts">
import Calc from './components/Calc.vue'
</script>
<template>
<main>
<Calc />
</main>
</template>
```
Теперь в браузере это будет выглядеть вот так:
ЭТАП 2
Теперь реализуем функционал добавления комнат:
```js
// Calc.vue
<script setup>
import { ref, computed } from "vue"
// пустой объект с параметрами комнаты
const emptyRoom = {
title: "",
length: 0,
width: 0,
}
// массив комнат, заполненный одной
const rooms = ref([
{...emptyRoom} // spread оператор используется для копирования полей объекта
])
// функция добавления новой комнаты в массив
const newRoom = () => {
rooms.value.push({
...emptyRoom
})
}
// функция удаления комнаты по индексу
const removeRoom = (index) => {
rooms.value.splice(index, 1)
}
</script>
...
```
Теперь свяжем верстку с данными в массиве.
Для этого используем цикл и будем связыть поля каждого объекта комнаты с полями ввода через v-model:
```js
// Calc.vue
...
<table>
<input
type="button"
value="+ Добавить комнату"
>
<template v-for="room, index in rooms">
<tr>
<th>Комната:</th>
<th><input type="text" v-model="room.title"></th>
</tr>
<tr>
<td>Длина</td>
<td><input type="number" v-model="room.length"></td>
</tr>
<tr>
<td>Ширина</td>
<td><input type="number" v-model="room.width"></td>
</tr>
<tr>
<td></td>
<td>
<input
type="button"
value="удалить комнату"
>
</td>
</tr>
</template>
</table>
...
```
Теперь добавим обработчики нажатий на кнопки:
```js
// Calc.vue
...
<input
type="button"
value="+ Добавить комнату"
@click="newRoom"
>
...
<input
type="button"
value="удалить комнату"
@click="removeRoom(index)"
>
...
```
Теперь мы можем добавлять и удалять комнаты, а также изменять параметры каждой:
ЭТАП 3
Реализуем логигу расчета стоимости в режиме реального времени.
В верстку на место "Итога" добавим вывод переменной resultPrice:
```js
// Calc.vue
...
<div>
Итог: {{ resultPrice }} руб
</div>
...
```
В секции script теперь объявим эту переменную как вычисляемое свойство
resultPrice:
```js
// Calc.vue
<script setup>
...
const PRICE_PER_METR2 = 50000 // стоимость кв метра
const resultPrice = computed(() => {
// расчет стоимости: для каждой комнаты перемножаем длину на ширину и на стоимость кв метра
let result = rooms.value.reduce((acc, room) => {
return acc += room.length * room.width * PRICE_PER_METR2
}, 0)
// результат преобразуем в строку, чтобы обеспечить локазиванный формат вывода числа (с отделением разрядов пробелами)
return result.toLocaleString()
})
...
```
В итоге получаем рабочий компонент:
Итоговый код копонента должен получится такой:
```js
// Calc.vue
<script setup>
import { ref, computed } from "vue"
// массив комнат
const emptyRoom = {
title: "",
length: 0,
width: 0,
}
const rooms = ref([
{...emptyRoom}
])
const newRoom = () => {
rooms.value.push({
...emptyRoom
})
}
const removeRoom = (index) => {
rooms.value.splice(index, 1)
}
// расчет
const PRICE_PER_METR2 = 50000
const resultPrice = computed(() => {
let result = rooms.value.reduce((acc, room) => {
return acc += room.length * room.width * PRICE_PER_METR2
}, 0)
return result.toLocaleString()
})
</script>
<template>
<input
type="button"
value="+ Добавить комнату"
@click="newRoom"
>
<table>
<template v-for="room, index in rooms">
<tr>
<th>Комната:</th>
<th><input type="text" v-model="room.title"></th>
</tr>
<tr>
<td>Длина</td>
<td><input type="number" v-model="room.length"> м.</td>
</tr>
<tr>
<td>Ширина</td>
<td><input type="number" v-model="room.width"> м.</td>
</tr>
<tr>
<td></td>
<td>
<input
type="button"
value="удалить комнату"
@click="removeRoom(index)"
>
</td>
</tr>
</template>
</table>
<div>
Итог: {{ resultPrice }} руб
</div>
</template>
```