复杂表单拆成多页,用户体验提升不止一倍

大家好,我是涛哥。在「智枢矩阵」表单编辑器中,除了拖拽排序、条件逻辑外,还有一个非常实用的功能:多页表单。当表单字段过多(比如超过20个)时,一次性展示所有字段会让用户感到压力,填完一页再进入下一页,体验会好很多。

今天我就把多页表单的核心实现拆解出来,分享给大家。无论你是开发问卷调查、订单提交、多步骤注册,还是任何需要分步填写的场景,都能直接复用。

一、需求分析

一个典型的多页表单需要满足:

  • 用户可以设置“是否启用分页”,以及每页显示多少个字段

  • 前端自动将字段按顺序分页,最后一页显示提交按钮

  • 顶部或底部显示当前页/总页数以及进度百分比

  • 支持上一步/下一步导航,切换时保留已填写的数据。

  • 提交时校验所有页的必填字段,不能只校验当前页。

二、数据结构设计

在表单的 schemaJson 中增加两个配置项:

{
  "enablePagination": true,
  "fieldsPerPage": 5,
  "fields": [ ... ]
}

前端核心状态:

const currentPage = ref(1);
const totalPages = ref(0);
const fields = ref([]);       // 所有字段(已排序)

totalPages 根据 fields.length / fieldsPerPage 向上取整计算。

注意:不是所有字段都参与分页,像“分割线”、“描述文字”这类辅助字段应该始终显示在当前页,不计入分页计数。我们定义“有效字段”为 type !== 'divider' && type !== 'description',只对有效字段进行分页。

const effectiveFields = fields.value.filter(f => !['divider', 'description'].includes(f.type));
totalPages.value = Math.ceil(effectiveFields.length / fieldsPerPage);

三、获取当前页的字段列表

核心算法:遍历所有字段,维持一个“有效字段索引”,只将属于当前页的有效字段加入结果,同时保留分割线和描述(它们不参与分页索引,但需要显示在对应页面)。

const getCurrentPageFields = () => {
  if (!enablePagination.value) return fields.value;

  const perPage = fieldsPerPage.value;
  let effectiveIndex = 0;
  const result = [];

  for (const field of fields.value) {
    // 辅助字段(分割线/描述)总是加入
    if (['divider', 'description'].includes(field.type)) {
      result.push(field);
      continue;
    }

    // 有效字段:计算属于哪一页
    const page = Math.floor(effectiveIndex / perPage);
    if (page + 1 === currentPage.value) {
      result.push(field);
    }
    effectiveIndex++;
  }
  return result;
};

这样,分割线和描述会出现在它们原本顺序所在的页面,不会丢失。


四、分页导航组件

模板

<template>
  <div class="pagination-nav">
    <div class="progress-info">
      第 {{ currentPage }} / {{ totalPages }} 页 · 进度 {{ progress }}%
    </div>
    <div class="progress-bar">
      <div class="progress-fill" :style="{ width: progress + '%' }"></div>
    </div>
    <div class="nav-buttons">
      <el-button v-if="currentPage > 1" @click="prevPage">上一步</el-button>
      <el-button v-if="currentPage < totalPages" type="primary" @click="nextPage">下一步</el-button>
      <el-button v-else type="primary" @click="submitForm">提交</el-button>
    </div>
  </div>
</template>

<script setup>
const progress = computed(() => Math.round((currentPage.value / totalPages.value) * 100));

const prevPage = () => {
  if (currentPage.value > 1) currentPage.value--;
};

const nextPage = () => {
  if (currentPage.value < totalPages.value) currentPage.value++;
};
</script>

进度条样式(简单实现):

.progress-bar {
  height: 8px;
  background: #e5e7eb;
  border-radius: 4px;
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #165DFF, #36D399);
  width: 0%;
  transition: width 0.3s ease;
}

五、数据保持与提交校验

数据保持formData 是全局响应式对象,切换页面不会丢失。

提交校验:必须校验所有页的必填字段,不能只校验当前页。

const validateAllPages = () => {
  const allFields = fields.value;
  const requiredFields = allFields.filter(f => f.required && !['divider', 'description'].includes(f.type));
  const missing = [];

  for (const field of requiredFields) {
    const value = formData.value[field.label];
    if (!value || (Array.isArray(value) && value.length === 0)) {
      missing.push(field.label);
    }
  }

  if (missing.length) {
    ElMessage.warning(`请填写完整:${missing.join('、')}`);
    return false;
  }
  return true;
};

提交时,如果校验失败,可以自动跳转到第一个错误字段所在的页面(需要额外实现字段与页面的映射)。


六、与条件逻辑的兼容

如果表单同时开启了条件显示,那么分页的计算会更加复杂。因为某些字段可能因条件不满足而隐藏,它们不应占用分页的“有效字段”位置。

解决方案:在计算 effectiveFields 之前,先根据当前 formData 过滤掉不可见的字段。每次 formData 变化时,重新计算 totalPages 并调整 currentPage(避免用户停在已不存在的页码上)。

watch(formData, () => {
  const visibleFields = fields.value.filter(f => isFieldVisible(f));
  effectiveFields.value = visibleFields.filter(f => !['divider', 'description'].includes(f.type));
  totalPages.value = Math.ceil(effectiveFields.value.length / fieldsPerPage.value);
  if (currentPage.value > totalPages.value) currentPage.value = totalPages.value;
}, { deep: true });

七、总结

通过合理的字段分页算法 + 简单的导航组件 + 进度指示,我们可以轻松实现多页表单。与条件逻辑联动时,只需动态重新计算可见字段即可。

这种模式不仅适用于表单系统,还可以用在多步骤配置向导、教学步骤引导等场景。

演示站https://zhishujuzhen.com
开源仓库https://gitcode.com/weixin_44479230/zhishu-matrix-open

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐