You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native:动画式问卷选ScrollView还是FlatList?

嘿,这个带动画分支的健康评估问卷需求很实用!我给你整理一个基于HTML/CSS/JavaScript的实现方案,完全满足你的跳转、动画和回退需求,一起来看看吧:

核心实现思路

我们可以把整个流程拆成数据结构定义、UI布局规划、动画交互逻辑和回退功能处理四个部分,一步步实现:

1. 定义问卷的分支数据结构

首先用数组对象把所有问题和选项的关联关系写清楚,每个选项对应下一个问题的ID,这样跳转逻辑会非常清晰:

const questionnaireData = [
  {
    id: 1,
    question: "你是否定期锻炼?",
    options: [
      { text: "是", value: "yes", nextQuestionId: 2 },
      { text: "否", value: "no", nextQuestionId: 3 }
    ]
  },
  {
    id: 2,
    question: "好的,你多久锻炼一次?",
    options: [
      { text: "每周3-5次", value: "3-5", nextQuestionId: 4 },
      { text: "每周1-2次", value: "1-2", nextQuestionId: 5 }
    ]
  },
  {
    id: 3,
    question: "那你平时有没有久坐的习惯?",
    options: [
      { text: "每天坐8小时以上", value: "long-sit", nextQuestionId: 6 },
      { text: "偶尔久坐", value: "short-sit", nextQuestionId: 7 }
    ]
  },
  // 可以继续扩展更多问题...
];

2. 规划UI布局

页面分成两个核心区域:

  • 顶部历史区:用来展示已经完成的问题和选中的选项,点击可以回退到对应步骤
  • 中间当前问题区:展示当前要回答的问题和选项

基础HTML结构示例:

<div class="questionnaire-container">
  <!-- 历史选择区 -->
  <div class="history-container"></div>
  <!-- 当前问题区 -->
  <div class="current-question"></div>
</div>

3. 实现动画效果

用CSS的transition来实现平滑的滑入滑出动画,让选中的问题/选项自然移动到顶部,新问题从右侧滑入:

.questionnaire-container {
  max-width: 600px;
  margin: 2rem auto;
  padding: 0 1rem;
}

.history-container {
  display: flex;
  gap: 1rem;
  margin-bottom: 2rem;
  flex-wrap: wrap;
}

.history-item {
  background: #f0f4f8;
  padding: 0.5rem 1rem;
  border-radius: 20px;
  cursor: pointer;
  transition: all 0.3s ease;
  transform: translateY(-20px);
  opacity: 0;
}
.history-item.show {
  transform: translateY(0);
  opacity: 1;
}
.history-item:hover {
  background: #e2e8f0;
}

.current-question {
  background: white;
  padding: 1.5rem;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  transition: all 0.3s ease;
}
.current-question.slide-out {
  transform: translateX(100%);
  opacity: 0;
}
.current-question.slide-in {
  transform: translateX(0);
  opacity: 1;
}

.option-list {
  list-style: none;
  padding: 0;
  margin-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}

.option-item {
  padding: 0.8rem 1rem;
  border: 1px solid #cbd5e1;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s ease;
}
.option-item:hover {
  background: #f8fafc;
}

4. 编写交互逻辑(JavaScript)

核心是维护一个历史栈,记录用户的每一步选择,实现跳转和回退功能:

let currentQuestionId = 1;
const historyStack = [];
const historyContainer = document.querySelector('.history-container');
const currentQuestionContainer = document.querySelector('.current-question');

// 渲染当前问题
function renderQuestion(questionId) {
  const question = questionnaireData.find(q => q.id === questionId);
  if (!question) return;

  // 清空当前容器并渲染内容
  currentQuestionContainer.innerHTML = `
    <h3>${question.question}</h3>
    <ul class="option-list">
      ${question.options.map(option => `
        <li class="option-item" data-next-id="${option.nextQuestionId}" data-text="${option.text}">
          ${option.text}
        </li>
      `).join('')}
    </ul>
  `;

  // 给选项绑定点击事件
  document.querySelectorAll('.option-item').forEach(item => {
    item.addEventListener('click', () => {
      const nextId = parseInt(item.dataset.nextId);
      const optionText = item.dataset.text;
      handleOptionSelect(optionText, nextId);
    });
  });

  // 重置动画类
  currentQuestionContainer.classList.remove('slide-out', 'slide-in');
  setTimeout(() => {
    currentQuestionContainer.classList.add('slide-in');
  }, 10);
}

// 处理选项选择(跳转下一题)
function handleOptionSelect(optionText, nextId) {
  // 将当前步骤加入历史栈
  historyStack.push({
    questionId: currentQuestionId,
    optionText: optionText
  });

  // 添加滑出动画
  currentQuestionContainer.classList.add('slide-out');

  // 动画结束后更新内容
  setTimeout(() => {
    currentQuestionId = nextId;
    renderQuestion(currentQuestionId);
    // 渲染新的历史项
    renderHistoryItem(historyStack[historyStack.length - 1]);
  }, 300);
}

// 渲染历史项到顶部
function renderHistoryItem(historyItem) {
  const itemEl = document.createElement('div');
  itemEl.className = 'history-item';
  itemEl.textContent = `${questionnaireData.find(q => q.id === historyItem.questionId).question}:${historyItem.optionText}`;
  // 绑定回退点击事件
  itemEl.addEventListener('click', () => {
    const index = historyStack.findIndex(item => item.questionId === historyItem.questionId);
    handleGoBack(index);
  });

  historyContainer.appendChild(itemEl);
  // 触发显示动画
  setTimeout(() => {
    itemEl.classList.add('show');
  }, 10);
}

// 处理回退操作
function handleGoBack(targetIndex) {
  // 移除目标索引之后的历史项
  const removedItems = historyStack.splice(targetIndex + 1);
  removedItems.forEach(() => {
    historyContainer.removeChild(historyContainer.lastChild);
  });

  // 跳转到目标问题
  currentQuestionId = historyStack[targetIndex].questionId;
  currentQuestionContainer.classList.add('slide-out');

  setTimeout(() => {
    renderQuestion(currentQuestionId);
  }, 300);
}

// 初始化渲染第一个问题
renderQuestion(currentQuestionId);

这样整个问卷就实现了你想要的所有功能:分支跳转、选中内容动画移到顶部、点击历史项回退。你可以根据需求修改样式和问题内容,扩展更多的分支逻辑~

内容的提问来源于stack exchange,提问作者HONGAA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:36:36