Разработка онлайн-калькулятора
Онлайн-калькулятор — один из самых эффективных лид-генерирующих инструментов на сайте. Посетитель вводит данные о своём проекте, видит ориентировочную стоимость или результат расчёта, и с высокой вероятностью оставляет контакт. Конверсия страниц с калькулятором в 2–5 раз выше, чем у статичных прайс-листов.
Типы калькуляторов
Стоимостной — «Сколько будет стоить разработка сайта / ремонт / SEO». Шаг за шагом уточняются параметры, итоговое число — диапазон.
ROI / Окупаемость — «Сколько вы сэкономите / заработаете с нашим продуктом». Вводятся текущие показатели, выводится экономия.
Технический — ипотечный калькулятор, расчёт материалов, конвертер единиц. Формула фиксирована.
Опросник с результатом — «Подберём тариф под вас». Multi-step форма, результат — рекомендация.
Архитектура формулы
Формула вычисляется на клиенте в реальном времени. Для сложных формул с ветвлением лучше описать логику как конфигурацию, а не хардкодить if-else:
interface CalculatorConfig {
inputs: InputDefinition[];
formula: FormulaDefinition;
output: OutputDefinition;
}
interface InputDefinition {
id: string;
type: 'number' | 'select' | 'checkbox' | 'range' | 'toggle';
label: string;
default: number | string | boolean;
min?: number;
max?: number;
step?: number;
options?: { value: string; label: string; multiplier?: number }[];
}
// Формула описывается как AST или простые функции
type FormulaFn = (inputs: Record<string, number>) => number;
Пример конфигурации для калькулятора стоимости разработки сайта:
const websiteCalculator: CalculatorConfig = {
inputs: [
{
id: 'page_count',
type: 'range',
label: 'Количество страниц',
default: 5,
min: 1,
max: 50,
step: 1,
},
{
id: 'site_type',
type: 'select',
label: 'Тип сайта',
default: 'landing',
options: [
{ value: 'landing', label: 'Landing page', multiplier: 1 },
{ value: 'corporate', label: 'Корпоративный', multiplier: 1.8 },
{ value: 'ecommerce', label: 'Интернет-магазин', multiplier: 3 },
{ value: 'custom', label: 'Сложный проект', multiplier: 5 },
],
},
{
id: 'has_cms',
type: 'toggle',
label: 'Система управления контентом (CMS)',
default: false,
},
{
id: 'has_seo',
type: 'checkbox',
label: 'SEO-оптимизация',
default: false,
},
],
};
Вычисление результата
const calculate = (inputs: Record<string, number | string | boolean>): CalculationResult => {
const basePrice = 50_000;
const typeMultipliers: Record<string, number> = {
landing: 1,
corporate: 1.8,
ecommerce: 3,
custom: 5,
};
const pageCount = inputs.page_count as number;
const siteType = inputs.site_type as string;
const hasCms = inputs.has_cms as boolean;
const hasSeo = inputs.has_seo as boolean;
let price = basePrice
* typeMultipliers[siteType]
* (1 + (pageCount - 1) * 0.08);
if (hasCms) price *= 1.3;
if (hasSeo) price += 25_000;
const min = Math.round(price * 0.8 / 1000) * 1000;
const max = Math.round(price * 1.3 / 1000) * 1000;
return { min, max, currency: 'RUB' };
};
React-компонент с real-time пересчётом
const Calculator: React.FC<{ config: CalculatorConfig }> = ({ config }) => {
const [inputs, setInputs] = useState<Record<string, unknown>>(() =>
Object.fromEntries(config.inputs.map(i => [i.id, i.default]))
);
const result = useMemo(() => calculate(inputs), [inputs]);
const handleChange = (id: string, value: unknown) => {
setInputs(prev => ({ ...prev, [id]: value }));
};
return (
<div className="calculator">
<div className="calculator__inputs">
{config.inputs.map(input => (
<CalculatorInput
key={input.id}
definition={input}
value={inputs[input.id]}
onChange={(val) => handleChange(input.id, val)}
/>
))}
</div>
<div className="calculator__result">
<AnimatedPrice value={result.min} /> — <AnimatedPrice value={result.max} />
<span className="currency"> ₽</span>
<p className="result__note">Ориентировочная стоимость. Точный расчёт — после брифинга.</p>
</div>
<LeadCaptureForm result={result} inputs={inputs} />
</div>
);
};
AnimatedPrice — компонент с framer-motion useSpring, число плавно «докручивается» при изменении параметров.
Форма захвата лида
После расчёта — форма с именем и телефоном/email:
const LeadCaptureForm: React.FC<{ result: CalculationResult; inputs: Record<string, unknown> }> = ({
result, inputs
}) => {
const { register, handleSubmit } = useForm<LeadFormData>();
const onSubmit = async (data: LeadFormData) => {
await api.post('/api/calculator-leads', {
...data,
calculator_result: result,
calculator_inputs: inputs,
page_url: window.location.href,
});
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('name')} placeholder="Ваше имя" />
<input {...register('phone')} placeholder="+7 (___) ___-__-__" />
<button type="submit">Получить точный расчёт</button>
</form>
);
};
Вся история ввода (calculator_inputs) сохраняется в базе — это ценные данные о том, что интересует пользователей.
Multi-step калькулятор
Для сложных расчётов лучше разбить на шаги — каждый шаг сужает выбор:
const steps = ['Тип проекта', 'Функциональность', 'Дизайн', 'Сроки'];
const [step, setStep] = useState(0);
return (
<div className="calculator-steps">
<StepIndicator steps={steps} current={step} />
<AnimatePresence mode="wait">
<motion.div
key={step}
initial={{ opacity: 0, x: 30 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -30 }}
transition={{ duration: 0.2 }}
>
<StepContent step={steps[step]} inputs={inputs} onChange={handleChange} />
</motion.div>
</AnimatePresence>
<div className="calculator-nav">
{step > 0 && <button onClick={() => setStep(s => s - 1)}>Назад</button>}
{step < steps.length - 1
? <button onClick={() => setStep(s => s + 1)}>Далее</button>
: <ResultAndForm result={result} />
}
</div>
</div>
);
Встраивание через iframe
Калькулятор можно сделать встраиваемым для партнёров:
<!-- Партнёрский сайт -->
<iframe
src="https://yoursite.com/calculator/embed?theme=dark&accent=%23ff6b35"
width="100%"
height="600"
frameborder="0"
></iframe>
Параметры темы и акцентного цвета передаются через query string, применяются через CSS-переменные.
Сроки
| Задача | Время |
|---|---|
| Базовый калькулятор (1 экран, real-time) | 0.5 дня |
| Лид-форма + сохранение в БД | 0.5 дня |
| Multi-step с анимацией | 1 день |
| Анимированный результат (spring-числа) | 0.5 дня |
Итого: 1.5–2.5 дня для большинства типов калькуляторов.







