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

Bootstrap Modal+PHP表单验证:提交后模态框自动关闭问题排查

问题核心原因

你当前使用的是表单原生同步提交机制,提交动作会触发整页刷新。Bootstrap Modal的显隐状态属于前端运行时内存状态,页面重载后所有前端状态会完全重置,模态框默认回到初始隐藏状态,自然不可能在刷新后保持开启,必须手动触发才能重新打开。

修复方案

根据项目实际情况二选一即可,优先推荐第一种方案,交互体验更好。

方案1:改用AJAX异步提交(推荐)

拦截表单默认提交行为,全程不触发页面重载,模态框会始终保持开启状态,提交后直接在当前弹窗内渲染返回结果即可:

  1. 前端拦截表单submit事件,第一时间调用preventDefault()阻止默认跳转
  2. FormData对象序列化表单数据(自动覆盖头像等文件上传域),通过异步请求发送到PHP后端
  3. 请求过程中可临时禁用提交按钮,避免重复提交
  4. 拿到后端返回的结果后,直接在模态框内渲染错误提示/成功提示,不需要做页面跳转

核心前端代码示例

原生JS写法(适配Bootstrap5):

const addUserForm = document.querySelector('#addUserModal form')
addUserForm.addEventListener('submit', async function(e) {
  // 阻止同步提交触发页面刷新
  e.preventDefault()
  const submitBtn = this.querySelector('button[type="submit"]')
  const tipArea = this.querySelector('.form-tip-area')
  submitBtn.disabled = true
  try {
    const formData = new FormData(this)
    const resp = await fetch('你的PHP处理接口路径', {
      method: 'POST',
      body: formData
    })
    const result = await resp.json()
    if(result.code !== 1) {
      tipArea.innerHTML = `<div class="alert alert-danger">${result.msg}</div>`
    } else {
      tipArea.innerHTML = `<div class="alert alert-success">${result.msg}</div>`
      this.reset() // 提交成功后按需清空表单
    }
  } catch (err) {
    tipArea.innerHTML = `<div class="alert alert-danger">请求异常,请稍后重试</div>`
  } finally {
    submitBtn.disabled = false
  }
})

老项目jQuery写法:

$('#addUserForm').on('submit', function(e) {
  e.preventDefault()
  const $form = $(this)
  const $submitBtn = $form.find('button[type="submit"]')
  $submitBtn.prop('disabled', true)
  $.ajax({
    url: '你的PHP处理接口路径',
    type: 'POST',
    data: new FormData(this),
    processData: false,
    contentType: false,
    dataType: 'json',
    success: function(res) {
      // 按返回结果渲染提示逻辑和原生写法一致
    },
    complete: function() {
      $submitBtn.prop('disabled', false)
    }
  })
})

对应PHP端调整

原有数据校验、头像上传、入库逻辑不需要改动,最终返回格式改为JSON输出即可,不要做页面跳转:

<?php
header('Content-Type: application/json');
// 原有校验逻辑
if (/* 校验不通过 */) {
  echo json_encode(['code' => 0, 'msg' => '具体错误信息,比如用户名长度不符合要求']);
  exit;
}
// 原有入库、上传逻辑
if (/* 操作失败 */) {
  echo json_encode(['code' => 0, 'msg' => '用户新增失败,请重试']);
  exit;
}
echo json_encode(['code' => 1, 'msg' => '用户新增成功']);
exit;
?>

注意:用AJAX上传文件时不要手动设置Content-Type请求头,浏览器会自动为FormData填充带分隔符的multipart/form-data头,手动设置会导致文件上传失败。

方案2:保留同步提交逻辑,重载后自动唤起模态框

如果暂时不想重构为异步提交,可以通过Session暂存提交结果,页面重载后判断存在提交结果时,自动调用Modal的显示方法唤起弹窗,同时渲染对应提示:

  1. PHP端处理完逻辑后,把提示信息、用户之前填的旧输入数据存入Session,再重定向回原表单页
  2. 原表单页渲染时判断Session中是否存在提交结果,如果存在就先把提示内容填充到模态框对应位置,再输出一段JS,在DOM加载完成后主动调用Modal的show方法打开弹窗
  3. 渲染完成后清除Session中存储的结果数据,避免刷新页面重复弹出提示
    核心逻辑示例:
// PHP处理接口逻辑末尾
session_start();
if ($校验失败) {
  $_SESSION['add_user_result'] = [
    'type' => 'error',
    'msg' => '具体错误提示',
    'old_input' => $_POST
  ];
  header('Location: 原表单页地址');
  exit;
}
// 成功逻辑同理存入Session后跳转

原表单页底部添加判断逻辑:

<?php
session_start();
if (isset($_SESSION['add_user_result'])):
  $result = $_SESSION['add_user_result'];
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
  // 先把提示内容填充到模态框的提示区域
  const tipArea = document.querySelector('#addUserModal .form-tip-area')
  tipArea.innerHTML = `<div class="alert alert-<?= $result['type'] === 'success' ? 'success' : 'danger' ?>"><?= $result['msg'] ?></div>`
  // 主动唤起模态框
  const userModal = new bootstrap.Modal(document.getElementById('addUserModal'))
  userModal.show()
})
</script>
<?php
  unset($_SESSION['add_user_result']); // 用完清除,避免重复提示
endif;
?>
避坑提醒
  • 提交逻辑中不要手动调用Modal的hide方法,否则会主动关闭弹窗
  • 如果是表单校验失败需要保留用户之前输入的内容,异步方案直接读取表单值回填即可,同步方案把之前存在Session的old_input数据输出到表单对应value属性中即可

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

火山引擎 最新活动