Answer the question
In order to leave comments, you need to log in
How to properly organize the code of a large calculator form in vue.js?
I'm creating my first form in vue.js and apparently I'm doing something wrong. The shape is big enough. When the number of lines of code exceeded 200, I decided that I needed to break the form into components block by block. As a result, it was necessary to take into account many nuances, and as a result, the code did not become simpler, but more complicated.
Apparently I'm doing something wrong, but there is no one to consult with. I hid my sheet of text and code so as not to unnerve those passing by. If someone has the time and desire to get acquainted and help with advice, I will be grateful.
<template>
<div id="app">
<h1>Калькулятор клининговых услуг</h1>
<form class="calculatorForm">
<Cleaning v-bind:item="cleaning" @input="updateCleaning(item)" ></Cleaning>
<button @click.prevent="getPriceInfo" >Рассчитать</button>
</form>
</div>
</template>
<script>
import Vue from 'vue'
import axios from 'axios'
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)
import { required, minLength, between, numeric } from 'vuelidate/lib/validators'
import { helpers } from 'vuelidate/lib/validators'
const mustBeCool = (value) => !helpers.req(value) || value.indexOf('cool') >= 0
import Carpet from './components/Carpet.vue'
import Cleaning from './components/Cleaning.vue'
axios.defaults.baseURL = 'https://site.ru/calculator/php'
export default {
name: 'app',
data () {
return {
services: ["cleaning","windows", "carpets","furniture"],
cleaning: {type: 2, area: null, showAbout: false, price: null, isActive: false},
windows: {isClassic:true, oneFoldCount: 0, twoFoldCount: 0, threeFoldCount: 0, area: null, isActive: false},
carpets: {items:[{type: 1, area: null}], isActive: false},
endpoint: '/index.php'
}
},
validations: {
cleaning: {
area:{
required
}
},
windows: {
oneFoldCount:{
numeric
},
twoFoldCount:{
numeric
},
threeFoldCount:{
numeric }
}
},
components: {Cleaning,Carpet},
methods: {
getPriceInfo: function(event) {
// Здесь будет код отправки данных для расчёта на сервер и получения стоимости услуг
},
updateCleaning: function(item) {
this.cleaning = item;
},
updateCarpet: function(item, index) {
this.carpets.items[index] = item;
},
addCarpet: function() {
this.carpets.items.push({type: 1, area: null});
}
}
}
</script>
<template>
<div class="serviceBlock" v-bind:class="{ active: isActive }" >
<div class="serviceSwitcher">
<label class="serviceName" for="serviceCleaning">Уборка
<input type="checkbox" id="serviceCleaning" value="cleaning" @change="isActive = !isActive" ><span class="checkmark"></span>
</label>
</div>
<div class="serviceContent" v-if="isActive">
<div class="serviceFields" >
<div class="fieldItem">
<label for="cleaningType">Тип уборки</label>
<select id="cleaningType" v-model="type">
<option disabled value="">Выберите один из вариантов</option>
<option value="1" >Быстрая</option>
<option value="2" >Генеральная</option>
<option value="3">После ремонта</option>
</select>
</div>
<div class="fieldItem">
<label for="cleaningArea">Площадь помещения (кв. м.)</label>
<input type="number" id="cleaningArea" min="1" v-model="area" v-on:input="filterArea">
</div>
</div>
<div class="servicePrice">
<div class="title">Стоимость уборки:</div>
<div class="value" v-if="price !== null" ><span class="price"></span><span class="currency">₽</span></div>
<div class="serviceErrors">
<div class="error" v-if="!$v.area.required">Введите площадь помещения, чтобы узнать стоимость уборки</div>
</div>
</div>
<div class="serviceDescription">
<a class="aboutLink" @click="showAbout = !showAbout" >Что входит в стоимость?</a>
<div class="aboutContent" v-if="showAbout" >Описание услуги</div>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)
import { required} from 'vuelidate/lib/validators'
export default {
name: 'Cleaning',
props:['item'],
data () {
return {
type: this.item.type,
area: this.item.area,
showAbout: this.item.showAbout,
price: this.item.price,
isActive: this.item.isActive
}
},
updated()
{
$this.$emit('updated', this.data());
},
methods: {
validateArea: function()
{
// Натуральное число
const templateArea = /^(?:[1-9]\d{0,4})$/;
if(templateArea.test(this.area))
{
return true;
}
return false;
},
filterArea: function(event) {
//Целое число или пустое значение
const templateArea = /^(?:[1-9]\d{0,4}|)$/;
if(templateArea.test(this.area))
{
this.previousArea = this.area;
}
else
{
this.area = this.previousArea;
}
},
}
}
</script>
Answer the question
In order to leave comments, you need to log in
Divide your Cleaning.vue component into Type.vue, Area.vue, Window.vue, etc., in which you implement the mechanics of each form element and its styling; for them you implement work through v-model:
<template>
<div class="fieldItem">
<label for="cleaningType">Тип уборки</label>
<select id="cleaningType" :value="value" @input="$emit('input', $event.value)">
<option disabled value="">Выберите один из вариантов</option>
<option value="1" >Быстрая</option>
<option value="2" >Генеральная</option>
<option value="3">После ремонта</option>
</select>
</div>
</template>
export default {
props: {
value: Number
}
}
<form class="calculatorForm">
<Type v-model="type" />
<Area v-model="area" />
<Window v-model="windows" />
....
<button @click.prevent="getPriceInfo" >Рассчитать</button>
</form>
not familiar with vue. but the code is understandable in principle, try to do this: all calculations in one file, all output in another.
in fact you will have 3 files. general (collecting)
so to speak "view" which inserts all the necessary data.
and a separate logic file. how it all unfolds for you.
it makes no sense to create a file for each button, just as it makes no sense to draw each button in a separate file
Connect the mobx library and take out all the logic from the templates, let the templates only transfer data to one of the mobx classes, and let the classes themselves decide what and where to display.
The form is the most common component of web pages. Now there are a lot of frameworks and libraries for solving standard tasks. For example, the lightweight Buefy framework for Vue (if you want, you can disable css styles, leaving only the js stuffing). Your code will be significantly reduced by using ready-made components. Reuse of FOREIGN code should become a habit for you.
Second, connect eslint and follow its instructions. You have a lot of indentation and places where the code can be made more compact. For example, I write like this:
if (var === true) {
do_something()
} else {
print_something()
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question