Formbricks问卷逻辑高级技巧:分支与跳转设置
引言:突破线性问卷的局限
你是否还在使用一成不变的线性问卷?当用户选择"非常满意"却被迫回答不满意原因时,当不同用户群体需要回答完全不同的问题序列时,传统问卷的局限性便暴露无遗。Formbricks的分支逻辑(Branching Logic)与跳转设置(Skip Logic)功能彻底改变了这一现状,允许你根据受访者的回答动态调整问卷流程,显著提升数据质量与用户体验。
读完本文,你将掌握:
- 分支与跳转逻辑的核心概念与应用场景
- 5种实用条件规则的配置方法
- 高级多条件组合与嵌套逻辑设计
- 逻辑冲突检测与性能优化技巧
- 3个真实业务场景的完整实现案例
- 调试与测试的专业工作流
核心概念:分支逻辑与跳转设置的工作原理
术语解析
| 术语 | 定义 | 应用场景 |
|---|---|---|
| 分支逻辑(Branching Logic) | 根据用户回答将问卷流程导向不同路径 | 产品反馈问卷根据评分展示不同问题序列 |
| 跳转设置(Skip Logic) | 满足特定条件时跳过一个或多个问题 | NPS评分9-10分的用户跳过改进建议问题 |
| 条件规则(Condition Rule) | 触发分支/跳转的判断依据 | 问题Q1的答案等于"是" |
| 动作(Action) | 满足条件后执行的操作 | 跳转到问题Q5、设为必填 |
| 逻辑运算符(Logical Operator) | 组合多个条件的连接方式 | AND(且)、OR(或)、NOT(非) |
工作流程图
技术实现原理
Formbricks通过QuestionConditional组件实现动态问卷逻辑,核心代码位于packages/surveys/src/components/general/question-conditional.tsx:
// 条件逻辑处理核心组件
export function QuestionConditional({
question,
value,
onChange,
onSubmit,
onBack,
// ...其他属性
}) {
useEffect(() => {
// 处理预填值自动跳过逻辑
if (value === undefined && (prefilledQuestionValue || prefilledQuestionValue === "")) {
if (skipPrefilled) {
onSubmit({ [question.id]: prefilledQuestionValue }, { [question.id]: 0 });
} else {
onChange({ [question.id]: prefilledQuestionValue });
}
}
}, []);
// 根据问题类型渲染不同的问题组件
return question.type === TSurveyQuestionTypeEnum.OpenText ? (
<OpenTextQuestion ... />
) : question.type === TSurveyQuestionTypeEnum.MultipleChoiceSingle ? (
<MultipleChoiceSingleQuestion ... />
) : (
// 其他问题类型...
null
);
}
逻辑评估通过evaluateLogic和performActions函数实现,在用户提交答案时动态计算下一步操作:
// 逻辑评估与动作执行示例(源自survey.test.tsx)
const logicModule = await import("@/lib/logic");
const performActions = vi.mocked(logicModule.performActions);
// 设置逻辑动作:跳转到q2并设为必填
performActions.mockReturnValue({
jumpTarget: "q2",
requiredQuestionIds: ["q2"],
calculations: {},
});
基础操作:条件规则配置指南
条件规则的5种基本类型
Formbricks支持丰富的条件判断类型,满足各种业务需求:
-
问题答案匹配
- 等于/不等于
- 包含/不包含
- 大于/小于(数字型)
- 之前/之后(日期型)
-
页面停留时间
- 大于X秒
- 小于Y秒
-
受访者属性
- 用户ID匹配
- 角色/权限
- 地理位置
-
提交历史
- 之前是否提交过
- 上次提交时间
-
URL参数
- 特定参数存在
- 参数值匹配
单条件跳转配置步骤
以NPS问卷为例,配置"9-10分跳过改进建议"的逻辑:
-
创建触发问题:添加NPS类型问题(Q1),标题"您对我们产品的满意度如何?"
-
添加条件规则:
{ "id": "c1", "questionId": "q1", "operator": "greaterThanOrEqual", "value": 9 } -
配置动作:
{ "id": "a1", "type": "jump", "target": "end1" } -
设置目标位置:创建结束卡片(end1),标题"感谢您的反馈!"
-
测试验证:使用Formbricks预览模式测试不同分数的跳转效果
配置示例代码
// 问题Q1的逻辑配置示例
const npsQuestion = {
id: "q1",
type: "nps",
headline: { default: "您对我们产品的满意度如何?" },
required: true,
logic: [
{
id: "logic1",
conditions: [
{
id: "c1",
questionId: "q1",
operator: "greaterThanOrEqual",
value: 9
}
],
actions: [
{
id: "a1",
type: "jump",
target: "end1"
}
]
}
]
};
高级应用:多条件组合与嵌套逻辑
逻辑运算符与优先级
Formbricks支持三种逻辑运算符,优先级从高到低为:
- NOT(非)
- AND(且)
- OR(或)
复杂条件示例:"收入>50000且(年龄>30或有房贷)"
{
"connector": "and",
"conditions": [
{
"questionId": "income",
"operator": "greaterThan",
"value": 50000
},
{
"connector": "or",
"conditions": [
{
"questionId": "age",
"operator": "greaterThan",
"value": 30
},
{
"questionId": "hasMortgage",
"operator": "equals",
"value": "true"
}
]
}
]
}
嵌套逻辑设计模式
1. 顺序决策树
2. 多路径合并
常见多条件场景代码实现
// 电商满意度问卷的复杂逻辑示例
const complexLogicSurvey = {
id: "survey-123",
questions: [
// Q1: 购买体验评分(1-5)
// Q2: 物流速度评分(1-5)
// Q3: 商品质量评分(1-5)
// Q4: 改进建议(仅当Q1-Q3有<3分时显示)
],
logic: [
{
id: "criticalFeedbackLogic",
conditions: {
"connector": "or",
"conditions": [
{ "questionId": "q1", "operator": "lessThan", "value": 3 },
{ "questionId": "q2", "operator": "lessThan", "value": 3 },
{ "questionId": "q3", "operator": "lessThan", "value": 3 }
]
},
actions: [
{ "type": "show", "target": "q4" },
{ "type": "require", "target": "q4" }
]
}
]
};
业务场景实战:从理论到实践
场景一:产品功能反馈问卷
目标:根据用户使用的功能模块,动态展示相关问题
逻辑设计:
- 多选问题Q1:"您使用过哪些功能?"(选项:A, B, C, D)
- 对每个选中的功能,展示对应的评分问题
- 未使用的功能模块跳过相关问题
实现代码:
// 功能选择与动态问题展示逻辑
const featureFeedbackLogic = [
{
id: "showFeatureAQuestions",
conditions: {
"questionId": "q1",
"operator": "includes",
"value": "featureA"
},
actions: [
{ "type": "show", "target": "q2" }, // Feature A满意度
{ "type": "show", "target": "q3" } // Feature A改进建议
]
},
{
id: "showFeatureBQuestions",
conditions: {
"questionId": "q1",
"operator": "includes",
"value": "featureB"
},
actions: [
{ "type": "show", "target": "q4" }, // Feature B满意度
{ "type": "show", "target": "q5" } // Feature B改进建议
]
}
// 其他功能模块逻辑...
];
流程图:
场景二:用户分层调研
目标:根据用户角色和使用频率,展示不同深度的问题
逻辑矩阵:
| 用户角色 | 低频用户(<1次/周) | 中频用户(1-3次/周) | 高频用户(>3次/周) |
|---|---|---|---|
| 普通用户 | 基础问题(5题) | 标准问题(8题) | 详细问题(12题) |
| 付费用户 | 标准问题(8题) | 详细问题(12题) | 深度问题(15题) |
| 管理员 | 标准问题(8题) | 详细问题(12题) | 专家问题(20题) |
核心逻辑代码:
// 用户分层逻辑实现
const userSegmentLogic = [
{
id: "basicUserLogic",
conditions: {
"connector": "and",
"conditions": [
{ "questionId": "role", "operator": "equals", "value": "user" },
{ "questionId": "frequency", "operator": "lessThan", "value": 1 }
]
},
actions: [
{ "type": "jump", "target": "basic-questions" },
{ "type": "limitQuestions", "count": 5 }
]
},
// 其他用户分层逻辑...
];
场景三:产品定价调研
目标:根据用户对各功能的付费意愿,动态计算价格区间
逻辑设计:
- 评分题Q1-Q5:对5个功能的付费意愿(1-5分)
- 条件逻辑:得分≥4的功能纳入价格计算
- 计算结果:基础价(¥99) + 每个高意愿功能(¥29)
- 展示个性化价格卡片和反馈问题
计算逻辑代码:
// 价格计算逻辑
const pricingLogic = {
id: "priceCalculation",
conditions: {
"connector": "and",
"conditions": [
{ "questionId": "q1", "operator": "greaterThanOrEqual", "value": 4 },
{ "questionId": "q2", "operator": "greaterThanOrEqual", "value": 4 }
// 其他功能条件...
]
},
actions: [
{
"type": "calculate",
"formula": "99 + (featureCount * 29)",
"targetVariable": "estimatedPrice"
},
{
"type": "show",
"target": "priceFeedback"
}
]
};
高级技巧与最佳实践
逻辑冲突检测与解决
Formbricks提供内置的逻辑冲突检测机制,常见冲突及解决方法:
-
循环引用:
- 症状:问卷陷入无限循环
- 解决:使用
isSubmitted条件避免重复触发
-
条件重叠:
- 症状:同一问题被多个矛盾逻辑规则控制
- 解决:使用优先级排序或合并条件
-
目标不存在:
- 症状:跳转目标问题已删除
- 解决:定期运行完整性检查工具
// 逻辑冲突检测工具示例代码
function detectLogicConflicts(survey) {
const conflicts = [];
// 检查循环引用
const visited = new Set();
function hasCycle(node, path = []) {
if (visited.has(node.id)) {
if (path.includes(node.id)) {
conflicts.push({
type: "cycle",
path: [...path, node.id]
});
}
return;
}
visited.add(node.id);
path.push(node.id);
node.logic?.forEach(logic => {
logic.actions.forEach(action => {
if (action.type === "jump") {
const targetNode = survey.questions.find(q => q.id === action.target);
if (targetNode) hasCycle(targetNode, [...path]);
}
});
});
path.pop();
}
// 从第一个问题开始检测
if (survey.questions.length > 0) {
hasCycle(survey.questions[0]);
}
return conflicts;
}
性能优化策略
-
逻辑简化:
- 合并相同条件的逻辑规则
- 使用变量存储重复计算结果
-
延迟加载:
- 非首屏问题逻辑延迟解析
- 条件不满足的问题组件不渲染
-
预计算:
- 提前计算可能的跳转路径
- 缓存逻辑评估结果
// 性能优化示例:逻辑预计算
function precomputeLogicPaths(survey) {
const paths = new Map();
function computePaths(questionId, currentPath = []) {
if (paths.has(questionId)) return paths.get(questionId);
const newPath = [...currentPath, questionId];
const question = survey.questions.find(q => q.id === questionId);
if (!question || !question.logic) {
const endPath = [...newPath, "end"];
paths.set(questionId, [endPath]);
return [endPath];
}
const allPaths = [];
question.logic.forEach(logic => {
logic.actions.forEach(action => {
if (action.type === "jump") {
const targetPaths = computePaths(action.target, newPath);
allPaths.push(...targetPaths);
}
});
});
// 添加默认路径
const nextQuestion = survey.questions.find(
q => q.order === question.order + 1
);
if (nextQuestion) {
const defaultPaths = computePaths(nextQuestion.id, newPath);
allPaths.push(...defaultPaths);
}
paths.set(questionId, allPaths);
return allPaths;
}
// 从第一个问题开始计算
if (survey.questions.length > 0) {
computePaths(survey.questions[0].id);
}
return paths;
}
可访问性与用户体验优化
-
进度提示:
- 动态更新进度条,反映实际剩余问题
- 预估完成时间,根据逻辑路径动态调整
-
导航控制:
- 允许返回修改,但保持逻辑一致性
- 提供"跳至结束"选项
-
错误处理:
- 清晰提示未满足的必填条件
- 提供保存草稿功能
调试与测试工作流
测试策略矩阵
| 测试类型 | 工具 | 覆盖率目标 | 关键检查点 |
|---|---|---|---|
| 单元测试 | Vitest | 逻辑代码80%+ | 条件评估、动作执行 |
| 集成测试 | Playwright | 主要路径100% | 跳转正确性、数据完整性 |
| 用户测试 | 真人测试 | 3-5名不同用户 | 流程直观性、错误提示 |
调试工具使用
Formbricks提供内置调试模式,启用后可:
- 查看当前逻辑评估状态
- 跟踪条件匹配过程
- 模拟不同的回答路径
- 导出逻辑流程图
自动化测试代码示例
// 问卷逻辑自动化测试示例
test("NPS逻辑跳转测试", async () => {
// 渲染问卷,从Q1开始
render(<Survey survey={npsSurvey} startAtQuestionId="q1" />);
// 测试9分跳转结束
fireEvent.change(screen.getByTestId("nps-slider"), { target: { value: 9 } });
fireEvent.click(screen.getByText("提交"));
await waitFor(() => {
expect(screen.getByTestId("ending-card")).toBeInTheDocument();
});
// 测试7分继续到Q2
rerender(<Survey survey={npsSurvey} startAtQuestionId="q1" />);
fireEvent.change(screen.getByTestId("nps-slider"), { target: { value: 7 } });
fireEvent.click(screen.getByText("提交"));
await waitFor(() => {
expect(screen.getByTestId("question-q2")).toBeInTheDocument();
});
});
总结与展望
Formbricks的分支与跳转逻辑为问卷设计带来了前所未有的灵活性和智能化。通过本文介绍的技巧,你可以构建真正个性化的调研体验,显著提升数据质量和用户参与度。
关键要点回顾:
- 分支逻辑允许根据条件展示不同问题路径
- 跳转设置可以跳过不必要的问题,减少用户负担
- 多条件组合实现复杂业务规则
- 逻辑冲突检测和性能优化确保流畅体验
- 完善的测试策略保障逻辑正确性
未来发展方向:
- AI辅助逻辑推荐
- 可视化逻辑编辑器
- 实时逻辑分析与优化建议
- 更丰富的条件类型与动作
掌握这些高级技巧后,你的问卷将不再是简单的问题集合,而成为真正的用户洞察引擎。现在就登录Formbricks,将这些技巧应用到你的下一份问卷中,体验智能调研的力量!
行动指南:
- 点赞收藏本文,作为日后配置逻辑的参考
- 立即前往Formbricks,尝试重构一份现有问卷
- 关注我们,获取更多Formbricks高级使用技巧
- 下期预告:《Formbricks API集成实战:从数据采集到业务自动化》
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



