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

使用Node.js与EJS时如何避免登录模态框在验证出错时关闭

弹窗登录表单验证错误自动关闭问题解决方法

根本原因

你当前使用的是表单同步提交逻辑,提交后会触发整页刷新,页面刷新后默认不会给弹窗元素添加active激活类,所以弹窗会自动关闭,用户无法看到返回的验证错误提示。

解决方案1:服务端渲染直接激活弹窗(改动最小)

无需修改表单提交逻辑,只需要调整EJS模板的弹窗渲染规则,存在错误时默认给弹窗添加激活类即可:

<!-- 将原有弹窗div修改为如下逻辑,存在错误时默认添加active类 -->
<div class="modal <%= errors && errors.length > 0 ? 'active' : '' %>">
  <div class="modal__box">
    <form id="login-form" action="/auth/login" method="POST">
      <h2>Login</h2>
      <% errors.forEach(function(message) { %>
        <div class="alert alert__danger">
          <p><%= message %></p>
        </div>
      <% }) %>
      <input type="email" placeholder="email" name="email">
      <input type="password" placeholder="password" name="password">
      <button id="modal-submit" class="btn">Login</button>
      <span class="modal__close"><i class="fas fa-times"></i></span>
    </form>
  </div>
</div>

注意:需要给input补充name属性,否则表单提交后后端无法拿到对应字段值。

解决方案2:异步提交表单(体验更优)

拦截表单默认提交行为,用AJAX异步提交数据,全程不刷新页面,弹窗不会自动关闭。

修改前端JS代码

class Nav {
  constructor(){
    this.modalBtn = document.querySelector('.modal__btn')
    this.modalBg = document.querySelector('.modal')
    this.modalCloseBtn = document.querySelector('.modal__close')
    this.loginForm = document.querySelector('#login-form')
    this.events()
  }

  events() {
    this.modalBtn.addEventListener('click', () => this.modalOpen())
    this.modalCloseBtn.addEventListener('click', () => this.modalClose())
    // 新增表单提交事件监听
    this.loginForm.addEventListener('submit', (e) => this.handleLoginSubmit(e))
  }

  modalOpen() {
    this.modalBg.classList.add('active')
  }

  modalClose() {
    this.modalBg.classList.remove('active')
    // 关闭弹窗时清空历史错误提示
    document.querySelectorAll('.alert__danger').forEach(el => el.remove())
  }

  // 新增异步提交处理方法
  async handleLoginSubmit(e) {
    e.preventDefault() // 阻止默认同步提交刷新页面
    const formData = new FormData(this.loginForm)
    const res = await fetch('/auth/login', {
      method: 'POST',
      body: formData
    })
    const result = await res.json()
    // 存在验证错误时直接渲染到弹窗内
    if(result.errors) {
      const errorHtml = result.errors.map(msg => `<div class="alert alert__danger"><p>${msg}</p></div>`).join('')
      this.loginForm.querySelector('h2').insertAdjacentHTML('afterend', errorHtml)
      return
    }
    // 登录成功跳转页面
    window.location.href = result.redirectUrl || '/dashboard'
  }
}

export default Nav

调整后端接口逻辑(以Express为例)

app.post('/auth/login', (req, res) => {
  const errors = []
  // 你的原有验证逻辑,将错误信息存入errors数组
  if(!req.body.email) errors.push('请输入邮箱地址')
  if(!req.body.password) errors.push('请输入登录密码')

  if(errors.length > 0) {
    // 判断是否为异步请求,是则返回JSON格式错误
    if(req.xhr || req.headers.accept.includes('json')) {
      return res.json({ errors })
    }
    // 兼容同步提交场景,返回原页面带错误信息
    return res.render('当前页面模板名', { errors })
  }

  // 验证通过逻辑
  if(req.xhr || req.headers.accept.includes('json')) {
    return res.json({ redirectUrl: '/dashboard' })
  }
  res.redirect('/dashboard')
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 21:21:02