פיתוח טופס אינטראקטיבי עם הסתעפות (לוגיקה מותנית) באתר שלך
לעתים קרובות אנו נתקלים במצב הבא: משתמש מתחיל למלא טופס עם 30 שדות, שרובם לא רלוונטיים עבורו. הוא ישות משפטית, אבל הוא רואה שדה לפרטי דרכון. הוא נוטש את הטופס באמצע הדרך. מצב זה הוא גורם נפוץ להמרה נמוכה. אנו פותרים זאת עם לוגיקה מותנית: שדות מוצגים או מוסתרים בהתאם לתשובות. כתוצאה מכך, כל משתמש רואה רק שאלות רלוונטיות, וההמרה עולה ב-20–40%. לפי מכון Baymard, טפסים ארוכים מפחיתים את ההמרה ב-80% — לוגיקה מותנית מפצה על השפעה זו. אנו מפתחים טפסים אינטראקטיביים עם הסתעפות במפתח מלא תוך 4–6 ימים.
כיצד פועלת לוגיקה מותנית בטופס
הרעיון המרכזי: הטופס מנוהל על ידי כללים המתוארים בקובץ תצורת JSON בשרת. ניתן לשנות את הלוגיקה ללא פריסה של הפרונטאנד — פשוט לעדכן את קובץ התצורה.
מנוע לוגיקה מותנית
interface FieldRule {
field: string; // поле, к которому применяется правило
action: 'show' | 'hide' | 'require' | 'set_value';
conditions: Condition[];
logic: 'and' | 'or';
}
interface Condition {
field: string;
operator: 'equals' | 'not_equals' | 'contains' | 'greater_than' | 'is_empty';
value: unknown;
}
function evaluateCondition(condition: Condition, formValues: Record<string, unknown>): boolean {
const fieldValue = formValues[condition.field];
switch (condition.operator) {
case 'equals':
return fieldValue === condition.value;
case 'not_equals':
return fieldValue !== condition.value;
case 'contains':
return String(fieldValue).includes(String(condition.value));
case 'is_empty':
return !fieldValue || fieldValue === '';
case 'greater_than':
return Number(fieldValue) > Number(condition.value);
default:
return false;
}
}
function shouldShowField(rule: FieldRule, formValues: Record<string, unknown>): boolean {
const results = rule.conditions.map(c => evaluateCondition(c, formValues));
return rule.logic === 'and' ? results.every(Boolean) : results.some(Boolean);
} רכיב טופס עם לוגיקה מותנית
function ConditionalForm({ schema, onSubmit }: Props) {
const { watch, register, handleSubmit } = useForm();
const formValues = watch();
const visibleFields = schema.fields.filter(field => {
const rule = schema.rules.find(r => r.field === field.id);
if (!rule) return true; // без правил — всегда показываем
return rule.action === 'show' ? shouldShowField(rule, formValues) : !shouldShowField(rule, formValues);
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<AnimatePresence>
{visibleFields.map(field => (
<motion.div
key={field.id}
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
>
<FormField field={field} register={register} />
</motion.div>
))}
</AnimatePresence>
<button type="submit">Отправить</button>
</form>
);
} למה לאחסן כללים בשרת?
שימו לב: כאשר הכללים מאוחסנים בשרת, משווק או מנהל יכולים לשנות את לוגיקת הטופס דרך פאנל ניהול ללא מעורבות מפתח. זה קריטי לבדיקות A/B ולתגובה מהירה להתנהגות משתמשים. תצורה בצד השרת מבטיחה התנהגות עקבית של הטופס בכל המכשירים וסנכרון עם ולידציה בצד השרת.
דוגמת תצורה
{
"fields": [
{
"id": "contact_type",
"type": "radio",
"options": ["Физлицо", "ИП", "ООО"]
},
{
"id": "company_name",
"type": "text",
"label": "Название компании"
},
{
"id": "inn",
"type": "text",
"label": "ИНН"
},
{
"id": "passport",
"type": "text",
"label": "Паспортные данные"
}
],
"rules": [
{
"field": "company_name",
"action": "show",
"logic": "or",
"conditions": [
{
"field": "contact_type",
"operator": "equals",
"value": "ИП"
},
{
"field": "contact_type",
"operator": "equals",
"value": "ООО"
}
]
},
{
"field": "passport",
"action": "show",
"logic": "and",
"conditions": [
{
"field": "contact_type",
"operator": "equals",
"value": "Физлицо"
}
]
}
]
}התצורה מאוחסנת בשרת — שינויי לוגיקה ללא פריסה.
השוואה: טופס עם לוגיקה מותנית לעומת טופס סטטי
| מאפיין | טופס סטטי | טופס עם הסתעפות |
|---|---|---|
| מספר שדות למשתמש | תמיד מקסימלי | רק רלוונטיים (הפחתה ב-40–60%) |
| גמישות בשינויים | דורש פריסה | שינויים דרך תצורת JSON |
| המרה | קו בסיס | גבוהה יותר ב-20–40% |
| מורכבות יישום | נמוכה | בינונית (דורש מנוע) |
הטופס עם ההסתעפות עולה על הטופס הסטטי בהמרה פי 1.5–2: לפי הנתונים שלנו, ההמרה גבוהה ב-20–40%, ומספר השדות מופחת ב-40–60%.
טבלה נוספת: אופרטורי תנאי
| אופרטור | תיאור | דוגמה |
|---|---|---|
interface FieldRule { field: string; // поле, к которому применяется правило action: 'show' | 'hide' | 'require' | 'set_value'; conditions: Condition[]; logic: 'and' | 'or'; } interface Condition { field: string; operator: 'equals' | 'not_equals' | 'contains' | 'greater_than' | 'is_empty'; value: unknown; } function evaluateCondition(condition: Condition, formValues: Record<string, unknown>): boolean { const fieldValue = formValues[condition.field]; switch (condition.operator) { case 'equals': return fieldValue === condition.value; case 'not_equals': return fieldValue !== condition.value; case 'contains': return String(fieldValue).includes(String(condition.value)); case 'is_empty': return !fieldValue || fieldValue === ''; case 'greater_than': return Number(fieldValue) > Number(condition.value); default: return false; } } function shouldShowField(rule: FieldRule, formValues: Record<string, unknown>): boolean { const results = rule.conditions.map(c => evaluateCondition(c, formValues)); return rule.logic === 'and' ? results.every(Boolean) : results.some(Boolean); } |
שוויון ערכים | function ConditionalForm({ schema, onSubmit }: Props) { const { watch, register, handleSubmit } = useForm(); const formValues = watch(); const visibleFields = schema.fields.filter(field => { const rule = schema.rules.find(r => r.field === field.id); if (!rule) return true; // без правил — всегда показываем return rule.action === 'show' ? shouldShowField(rule, formValues) : !shouldShowField(rule, formValues); }); return ( <form onSubmit={handleSubmit(onSubmit)}> <AnimatePresence> {visibleFields.map(field => ( <motion.div key={field.id} initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: 'auto' }} exit={{ opacity: 0, height: 0 }} > <FormField field={field} register={register} /> </motion.div> ))} </AnimatePresence> <button type="submit">Отправить</button> </form> ); } |
{ "fields": [ { "id": "contact_type", "type": "radio", "options": ["Физлицо", "ИП", "ООО"] }, { "id": "company_name", "type": "text", "label": "Название компании" }, { "id": "inn", "type": "text", "label": "ИНН" }, { "id": "passport", "type": "text", "label": "Паспортные данные" } ], "rules": [ { "field": "company_name", "action": "show", "logic": "or", "conditions": [ { "field": "contact_type", "operator": "equals", "value": "ИП" }, { "field": "contact_type", "operator": "equals", "value": "ООО" } ] }, { "field": "passport", "action": "show", "logic": "and", "conditions": [ { "field": "contact_type", "operator": "equals", "value": "Физлицо" } ] } ] } |
אי-שוויון | equals |
"contact_type" == "ИП" |
הכללת תת-מחרוזת | not_equals |
"status" != "active" |
גדול מספרית מ- | contains |
"email" contains "@" |
שדה ריק | greater_than |
כיצד להימנע מבעיות ביצועים?
עם שדות רבים (50+) וכללים מורכבים, בדיקות תנאים עלולות לגרום לעיכובים. הפתרון הוא מזמוז (memoization) של שדות מחושבים ו-debounce על watch. במנוע שלנו, כל קריאה ל-"age" > 18 נשמרת במטמון עד שהשדה התלוי משתנה. זה מפחית את עומס העיבוד לכמה מילישניות גם בטפסים עם מאה שדות. בנוסף, אנו משתמשים ב-debounce של 300ms על watch כדי להימנע מחישובים מיותרים.
טעויות יישום אופייניות
הטעות הראשונה היא אי-התחשבות במקרי קצה. לדוגמה, כאשר משנים בחירה שכבר הסתירה שדות אחרים, יש לנקות כראוי את הערכים של אותם שדות. השנייה היא חוסר ולידציה בצד השרת: לוגיקת צד לקוח ניתנת לעקיפה, ולכן כל הכללים משוכפלים בקצה האחורי. השלישית היא שרשראות תלות מורכבות: אם שדה A תלוי ב-B, ו-B תלוי ב-A, נוצרת תלות מעגלית. יש לזהות זאת בזמן טעינת התצורה. הרביעית היא חוסר תיעוד לוג של הפעלות כללים, מה שמסבך את הניפוי.
תהליך העבודה
- אנליטיקה — דנים בתרחישים, מציירים מפת חשיבה של הסתעפות.
- עיצוב — מגדירים סכמת כללי JSON, קובעים סוגי שדות.
- יישום — כותבים את המנוע, הרכיבים והקונפיגורטור.
- בדיקות — בודקים את כל שרשראות התנאים, כולל מקרי קצה.
- פריסה — פורסים לסביבת ייצור, מעניקים גישה לקונפיגורטור.
- תמיכה — עונים על שאלות ומתקנים באגים במשך 30 יום לאחר המסירה.
מה כלול בפיתוח
- עיצוב סכמת כללי JSON וסוגי שדות
- פיתוח מנוע הלוגיקה המותנית (רכיבי React + מנתח שרת)
- אינטגרציה עם ה-CRM שלך או כל API (Bitrix24, AmoCRM, HubSpot)
- פאנל ניהול לניהול כללים ללא פריסה
- תיעוד תצורה
- הכשרת מנהלים לשימוש בקונפיגורטור
- תמיכה טכנית ל-30 יום
לוחות זמנים ועלות
טופס עם מנוע לוגיקה מותנית ותצורת JSON מפותח תוך 4–6 ימי עסקים. העלות מחושבת באופן אישי, בהתאם למורכבות האינטגרציה ומספר התרחישים. לוח הזמנים עשוי להתארך עם אינטגרציות מורכבות או אנימציות לא סטנדרטיות — אנו מעריכים כל פרויקט בנפרד. טפסי React מותאמים אישית עם תצורת שרת הם המומחיות שלנו, עם למעלה מ-50 יישומים.
הזמינו טופס עם לוגיקה מותנית לפרויקט שלכם — ננתח את המשימה תוך יום עסקים אחד. קבלו ייעוץ — ננתח את המשימה שלכם ונציע את הפתרון האופטימלי. למהנדסים שלנו יש למעלה מ-10 שנות ניסיון בפיתוח אתרים ולמעלה מ-50 יישומי טפסים עם הסתעפות. אנו מבטיחים פעולה יציבה ותמיכה מהירה לאחר המסירה. החיסכון בתקציב משימוש בתצורת שרת מגיע עד 50% בשינויים, והעלות קבועה בחוזה.







