多步骤表单示例

多步骤表单管理概览

构建流畅的分步式表单体验,提升用户填写效率和完成率

此示例演示如何使用kinlink API创建多步骤表单,通过分段填写的方式提升用户体验。系统会自动管理步骤切换、数据验证和进度展示,让复杂表单变得简单易用。

多步骤表单核心功能

  • 📝 分步导航:清晰的步骤指示和进度展示
  • 智能验证:每步完成前的数据校验
  • 💾 自动保存:实时保存用户输入数据
  • 🔄 灵活切换:支持前进、后退和跳转
  • 📱 响应式设计:适配各种屏幕尺寸
  • 🎯 用户引导:清晰的操作指引和提示

关键功能

  • 动态步骤管理和导航
  • 分步数据验证和提交
  • 进度指示和视觉反馈
  • 自动保存和恢复机制

代码示例

此示例展示了多步骤表单的完整实现,包括步骤配置、导航控制、验证逻辑和摘要页面。

完整代码请下载查看:

13-多步骤表单提交处理.js

/**
* 示例13: 多步骤表单提交处理
* 功能:创建多步骤表单,包括步骤导航、进度指示器、分步验证和提交前摘要页面
*/
(function () {
// 步骤配置
const steps = [
  {
    title: '基本信息',
    icon: '📋',
    fields: [
      '文字列__1行__0',
      '文字列__1行__1',
      '单行文本框_8',
      '单行文本框_9',
      '单选框_0',
      '日期_1',
      '多选_0',
      '表格',
      '表格_13',
    ],
  },
  {
    title: '联系方式',
    icon: '📞',
    fields: ['文字列__1行__2', '文字列__1行__3', '单行文本框_10', '下拉菜单'],
  },
  {
    title: '证件信息',
    icon: '📝',
    fields: ['单行文本框_11', '日期_2', '附件_0'],
  },
  {
    title: '确认提交',
    icon: '✅',
    fields: [], // 最后一步显示所有信息摘要,不指定具体字段
  },
];

// 当前步骤
let currentStep = 0;

// 表单加载完成时的初始化
kinlink.events.on(kinlink.FormEvents.FORM_LOADED, () => {
  try {
    // 隐藏官方UI元素
    kinlink.formApi.hideKintoneLabel();
    kinlink.formApi.hideKintoneCollapse();
    kinlink.layoutApi.hideSubmitButton();
    kinlink.layoutApi.hideHeader();
    
    if (kinlink.layoutApi.checkIsMobileDevice()) {
      kinlink.layoutApi.mobileHideFormActionBar();
    }

    // 创建自定义UI
    createCustomUI();
    showStep(currentStep);
    applyGlobalStyles();

    // 注册提交后事件处理
    kinlink.events.on(kinlink.FormEvents.AFTER_SUBMIT, (data) => {
      if (data && data.success) {
        showSuccessScreen();
      }
    });
  } catch (error) {
    console.error('多步骤表单初始化失败:', error);
  }
});

// 创建自定义UI
function createCustomUI() {
  createHeader();
  createStepNavigation();
  createButtons();
  createSuccessScreen();
}

// 创建页面头部
function createHeader() {
  const header = document.createElement('div');
  header.id = 'multi-step-header';
  header.style.cssText = `
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    padding: 2rem;
    text-align: center;
    margin-bottom: 2rem;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0,0,0,0.1);
  `;

  header.innerHTML = `
    <h1 style="margin: 0; font-size: 2rem; font-weight: bold;">申请表单</h1>
    <p style="margin: 0.5rem 0 0 0; opacity: 0.9;">请按步骤完成信息填写</p>
  `;

  const formElement = document.querySelector('.ant-form') || document.body;
  formElement.insertBefore(header, formElement.firstChild);
}

// 显示特定步骤
function showStep(stepIndex) {
  const form = kinlink.formApi;

  // 隐藏所有字段
  steps.forEach((step) => {
    step.fields.forEach((field) => {
      form.visuallyHideField(field);
    });
  });

  // 如果是最后一步,显示摘要页面
  if (stepIndex === steps.length - 1) {
    showSummaryPage();
  } else {
    // 显示当前步骤的字段
    steps[stepIndex].fields.forEach((field) => {
      form.showField(field);
    });
    hideSummaryPage();
  }

  // 更新UI状态
  updateStepNavigation(stepIndex);
  updateButtons(stepIndex);
  currentStep = stepIndex;
}

// 验证当前步骤
function validateCurrentStep() {
  const form = kinlink.formApi;
  const currentStepFields = steps[currentStep].fields;
  const values = form.getAllValues();
  let isValid = true;

  currentStepFields.forEach((field) => {
    const fieldConfig = kinlink.formFields[field];
    if (fieldConfig && fieldConfig.required && !values[field]) {
      form.setFieldError(field, `${fieldConfig.label}は必須項目です`);
      isValid = false;
    }
  });

  if (!isValid) {
    kinlink.formApi.showError('必須項目をご入力ください', 3);
  }

  return isValid;
}

// 导航到指定步骤
function navigateToStep(stepIndex) {
  if (stepIndex >= 0 && stepIndex < steps.length) {
    showStep(stepIndex);
    window.scrollTo({ top: 0, behavior: 'smooth' });
  }
}

// 显示摘要页面
function showSummaryPage() {
  let summaryDiv = document.getElementById('step-summary-view');
  if (summaryDiv) summaryDiv.remove();

  summaryDiv = document.createElement('div');
  summaryDiv.id = 'step-summary-view';
  summaryDiv.style.cssText = `
    margin: 32px 0 0 0;
    background: #fafbfc;
    border-radius: 8px;
    box-shadow: 0 1px 8px 0 rgba(0,0,0,0.03);
    padding: 32px 24px;
  `;

  const title = document.createElement('h3');
  title.textContent = '入力内容の確認';
  title.style.cssText = `
    margin: 0 0 24px 0;
    font-size: 20px;
    font-weight: bold;
    color: #333;
  `;
  summaryDiv.appendChild(title);

  // 获取所有表单值并按步骤显示
  const values = kinlink.formApi.getAllValues();
  
  steps.slice(0, -1).forEach((step, stepIndex) => {
    const stepDiv = document.createElement('div');
    stepDiv.style.marginBottom = '24px';

    const stepTitle = document.createElement('h4');
    stepTitle.textContent = `${step.icon} ${step.title}`;
    stepTitle.style.cssText = `
      margin: 0 0 12px 0;
      font-size: 16px;
      font-weight: bold;
      color: #555;
    `;
    stepDiv.appendChild(stepTitle);

    step.fields.forEach((field) => {
      const value = values[field];
      if (value) {
        const fieldDiv = document.createElement('div');
        fieldDiv.style.cssText = `
          display: flex;
          margin-bottom: 8px;
          padding: 8px 0;
          border-bottom: 1px solid #eee;
        `;

        const label = document.createElement('span');
        label.textContent = field + ':';
        label.style.cssText = `
          min-width: 120px;
          font-weight: 500;
          color: #666;
        `;

        const valueSpan = document.createElement('span');
        valueSpan.textContent = Array.isArray(value) ? value.join(', ') : value;
        valueSpan.style.color = '#333';

        fieldDiv.appendChild(label);
        fieldDiv.appendChild(valueSpan);
        stepDiv.appendChild(fieldDiv);
      }
    });

    summaryDiv.appendChild(stepDiv);
  });

  const formElement = document.querySelector('.ant-form') || document.body;
  formElement.appendChild(summaryDiv);
}

// 应用全局样式
function applyGlobalStyles() {
  const style = document.createElement('style');
  style.textContent = `
    .multi-step-container {
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
    }
    
    .step-navigation {
      display: flex;
      justify-content: center;
      margin-bottom: 2rem;
      flex-wrap: wrap;
    }
    
    .step-item {
      display: flex;
      align-items: center;
      margin: 0 10px;
      padding: 10px 15px;
      border-radius: 25px;
      cursor: pointer;
      transition: all 0.3s ease;
    }
    
    .step-item.active {
      background: #667eea;
      color: white;
    }
    
    .step-item.completed {
      background: #48bb78;
      color: white;
    }
    
    .step-buttons {
      display: flex;
      justify-content: space-between;
      margin-top: 2rem;
      gap: 1rem;
    }
    
    @media (max-width: 768px) {
      .step-navigation {
        flex-direction: column;
        align-items: center;
      }
      
      .step-item {
        margin: 5px 0;
        width: 100%;
        max-width: 300px;
        justify-content: center;
      }
      
      .step-buttons {
        flex-direction: column;
      }
    }
  `;
  document.head.appendChild(style);
}
})();

实现特性

  • 响应式设计:自动适配移动端和桌面端

  • 进度指示:清晰显示当前步骤和总体进度

  • 分步验证:每步完成时验证当前步骤的字段

  • 数据摘要:最后一步显示所有输入数据的摘要

  • 灵活导航:支持前进、后退和直接跳转到特定步骤

  • 自定义样式:可以根据品牌需求自定义外观

使用说明

  1. 根据您的表单字段修改步骤配置
  2. 调整验证规则以匹配您的业务需求
  3. 自定义步骤标题和图标
  4. 根据需要修改样式和布局
  5. 测试所有步骤的导航和验证功能

注意事项

确保在每个步骤中包含所有必要的字段,并为每个步骤设置适当的验证规则。在移动设备上测试导航和用户体验。

API参考

此示例使用了以下kinlink API:
  • kinlink.formApi.visuallyHideField(fieldCode) - 视觉隐藏字段

  • kinlink.formApi.showField(fieldCode) - 显示字段

  • kinlink.formApi.getAllValues() - 获取所有表单值

  • kinlink.formApi.setFieldError(fieldCode, message) - 设置字段错误

  • kinlink.formApi.showError(message, duration) - 显示错误消息

  • kinlink.formApi.submit() - 提交表单