Простой калькулятор стоимости на jQuery

Здесь напишем небольшой калькулятор, который будет выполнять подсчет стоимости работ, услуг, еще чего-то (подробности ниже).

Есть таблица, в которой список работ и цены к ним, примерно вот такая:

Услуга Кол-во ед. изм. Цена (р)
Написать статью 1000 зн. 50
Вбить гвоздь 5 шт. 100
Подумать 10 мин. 150
Выдернуть гвоздь 1 шт 20

И ее вид в коде:

<table border="1" cellpadding="5" cellspacing="0" width="100%">
<tr>
	<td>Услуга</td>
	<td>Кол-во</td>
	<td>ед. изм.</td>
	<td>Цена (р)</td>
</tr>
<tr>
	<td>Написать статью</td>
	<td>1000</td>
	<td>зн.</td>
	<td>50</td>
</tr>
<tr>
	<td>Вбить гвоздь</td>
	<td>5</td>
	<td>шт.</td>
	<td>100</td>
</tr>
<tr>
	<td>Подумать</td>
	<td>10</td>
	<td>мин.</td>
	<td>150</td>
</tr>
<tr>
	<td>Выдернуть гвоздь</td>
	<td>1</td>
	<td>шт</td>
	<td>20</td>
</tr>
</table>

Здесь есть несколько работ, с разными единицами измерения (что вообще не важно), разным минимальным количеством, ценой.

Что нужно сделать (небольшое ТЗ)

  1. Сделать количество в виде поля, с возможностью ввода произвольного значения
  2. В поле "Количество" должны быть кнопки +/- для изменения значения с заданным интервалом, шагом (для одних работ добавлять +1, для других +5, +20 и т.д.)
  3. Шаг может отличаться от минимального количества. Например: стоимость "Написание статьи" минимально указана за 1000 знаков, а в дальнейшем нужно добавлять +200 знаков за шаг.
  4. Произвольно вводимые значения должны соответствовать указанному шагу. Т.е. при шаге "5" и попытке указать вручную "2", значение должно автоматом меняться на "5".
  5. После таблицы должна быть сумма "Итого"

Что будем делать

  1. Добавить поле input для ввода количества
  2. Добавить в таблицу "Шаг" (этого параметра у нас нет). Можно в виде скрытого поля, видимого значения, или атрибута. Здесь уж как удобнее. Я буду делать атрибутом для поля ввода количества
  3. К input добавить +/-
  4. Добавить классы элементам с данными (в данном случае - ячейки таблицы, но это могут быть и блоки)
  5. Написать небольшой скрипт, чтобы это работало

Реализация. Шаг 1

Для начала добавлю в талицу классы и недостающее поле. Получится так:

<table border="1" cellpadding="5" cellspacing="0" width="100%" class="calc">
<tr>
	<td>Услуга</td>
	<td>Кол-во</td>
	<td>ед. изм.</td>
	<td>Цена (р)</td>
</tr>
<tr class="t-row">
	<td>Написать статью</td>
	<td>
		<div class="inp-group">
		<input type="text" name="quant" value="0" class="quant form-control" data-step="200" data-price="10" data-min="1000" />
		<span class="plus minpl">+</span>
		<span class="minus minpl">-</span>
		</div>
	</td>
	<td>знаков</td>
	<td class="price">0</td>
</tr>
<tr class="t-row">
	<td>Вбить гвоздь</td>
	<td>
		<div class="inp-group">
		<input type="text" name="quant" value="0" class="quant form-control" data-step="5" data-price="20" data-min="5" />
		<span class="plus minpl">+</span>
		<span class="minus minpl">-</span>
		</div>
	</td>
	<td>шт.</td>
	<td class="price">0</td>
</tr>
<tr class="t-row">
	<td>Подумать</td>
	<td>
		<div class="inp-group">
		<input type="text" name="quant" value="0" class="quant form-control" data-step="1" data-price="15" data-min="10" />
		<span class="plus minpl">+</span>
		<span class="minus minpl">-</span>
		</div>
	</td>
	<td>мин.</td>
	<td class="price">0</td>
</tr>
<tr class="t-row">
	<td>Выдернуть гвоздь</td>
	<td>
		<div class="inp-group">
		<input type="text" name="quant" value="0" class="quant form-control" data-step="1" data-price="20" data-min="1" />
		<span class="plus minpl">+</span>
		<span class="minus minpl">-</span>
		</div>
	</td>
	<td>шт</td>
	<td class="price">0</td>
</tr>
</table>
<p class="text-center result">Итого:<br /><span class="val">0</span> руб.</p>

Эта же таблица на странице:

Услуга Кол-во ед. изм. Цена (р)
Написать статью
+ -
знаков 0
Вбить гвоздь
+ -
шт. 0
Подумать
+ -
мин. 0
Выдернуть гвоздь
+ -
шт 0

Итого:
0 руб.

Что здесь для чего и почему:

  • Вместо количества появилось поле "quant" с атрибутами data-step (шаг), data-price (цена шага), data-min (минимальное количество)
  • Строкам добавлен класс "t-row" для нахождения родителя в js. Добавил для легкой переделки из таблицы в блоки (можно было обращаться и к тегу "tr")
  • Для всей таблицы добавлен класс "calc". Таких таблиц на странице может быть сколько угодно, используем этот класс, соблюдаем структуру и все будет работать одним скриптом
  • Цена установлена = 0 и добавлен класс "price" - для нахождения блока скриптом

Реализация. Пишем скрипт

Т.к. скрипт будет работать с использованием библиотеки jQuery, ее необходимо подключить, что скорее всего уже и так сделано (идет в комплекте с большинством шаблонов, тем, включена как стандартная у многих CMS).

Будет три функции: две будут менять значение input, в зависимости от способа изменения - по кнопкам, или путем ввода с клавиатуры. Третья будет подсчитывать цену и выводить итого.

<script>
/*Обрабатываем нажатия на кнопки + и - */
$('.minpl').click(function() {
/*Находим input*/
	$input = $(this).parent().find('.quant');
	var qty = Number($input.val());
/*На случай, если количество не удалось определить (например, пользователь мог оставить поле пустым)*/
	if (isNaN(qty)) qty = 0;
	if ($(this).hasClass('plus')) {
		if (qty == 0) {
			qty = $input.data('min');
		} else {
			qty += $input.data('step');
		}
	} else {
		qty -= $input.data('step');
	}
    var min = $input.data('min');
    if (qty >= min)  {
        $input.val(qty).trigger('input');
    } else {
 		$input.val(0).trigger('input');
	}
/*Передаем функции подсчета, обновления*/
	updateCalc($input);
});
/*Обрабатываем ввод с клавиатуры */
$('.quant').change(function() {
	var qty = $(this).val();
	if (isNaN(qty)) qty = 0;
	var min = $(this).data('min');
	var step = $(this).data('step');
	if (qty > 0)  {
/*Если вдруг число не кратно шагу, увеличиваем (только увеличение) до кратного*/
		qty = Math.ceil(qty/step)*step;
		if (qty < min) {
			qty = min;
		}
        $(this).val(qty).trigger('input');
    } else {
 		$(this).val(0).trigger('input');
	}
	updateCalc($(this));
});
/*Считаем, обновляем значения*/
function updateCalc($input){
	var qty = Number($input.val());
	if (isNaN(qty)) qty = 0;
	$input.parents('.t-row').find('.price').text(qty * $input.data('price')/$input.data('step'));
	var itog = 0;
	$input.parents('.calc').find('.price').each(function(){
		itog += parseInt($(this).text());
	});
	$input.parents('.calc').next().find('.val').text(itog);
}
</script>

Шаг последний. Немного оформим в CSS

<style>
.inp-group {position: relative;padding-right: 20px;display: block;}
.inp-group .quant {border: 1px solid #636363;box-sizing:border-box;}
.inp-group .minpl {position: absolute;height: 50%;box-sizing: border-box;right: 0px;display: block;text-align: center;width: 20px;line-height: 18px;background: #3d5354;color: #079de6;cursor: pointer;border: 1px solid #636363;}
.inp-group .minpl:hover {background:#354455;}
.inp-group .plus {top: 0px}
.inp-group .minus {bottom: 0px}
</style>
Сказать $пасибо

Комментарии ()