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

如何校验所有表单字段填写完成后启用提交按钮,提交后禁用5秒

实现目标

实现表单提交按钮的状态控制逻辑:仅当所有输入框均填写有效值时,才enable提交按钮;点击提交后按钮保持disabled状态5秒,防止重复提交。

现有代码

Blade模板表单结构

<form method="POST" id="contactForm">
 <div class="row">
   <div class="col-6">
     <input type="text" name="name" id="name" value=""/>
     <div class="error">Error Message</div>
   </div>
   <div class="col-6">
     <input type="text" name="email" id="email" value=""/>
     <div class="error">Error Message</div>
   </div>
   <div class="col-12">
     <textarea name="body" id="message" rows="5"> Enter your message</textarea>
        <div class="error">Error message</div>
   </div>
   <div class="col-12">
      <input type="submit" value="Submit" class="primary" id="buttonSubmit" disabled/>
   </div>
</div>
</form>

后端Controller校验逻辑

后端已经添加必填规则校验:

public  function store()
{
$data = request()->validate([
         'name' => 'required',
         'email'   => 'required|email',
         'body' =>  'required',
        ]);
}

现有前端控制脚本

const button = document.querySelector("#buttonSubmit");
const buttonExpirationDataKey = 'button-disabled-expiration';
button.addEventListener("click", () => {
  var form = document.getElementById("contactForm");
  var fields = ["name", "email","body"];
  var i, l = fields.length;
  var fieldname;
  for (i = 0; i < l; i++) {
    fieldname = fields[i];
    if(form[fieldname].value  !== ""){
      button.disabled = true;
      let now = new Date();
      let expirationTime = 1000 * 5; // 5 secs to disable the submit button
      let expirationDate = new Date(now.getTime() + expirationTime);
      localStorage.setItem(buttonExpirationDataKey, expirationDate);
      button.dataset.enabledAt = expirationDate;
    }
    else {
      button.disabled = false;
    }
    return false;
  }
});
现存问题

当前代码存在5个核心错误:

  • 提交按钮初始状态为disabled,浏览器默认不会响应disabled元素的点击事件,原代码把所有状态判断逻辑都绑定在按钮的click事件上,逻辑从根源上无法正常执行
  • for循环内部第一趟遍历就执行了return false,直接终止循环,根本不会校验后续字段
  • 按钮状态判断逻辑完全写反:只要单个字段非空就禁用按钮,遇到空字段就启用按钮,和需求逻辑完全颠倒
  • 没有绑定输入事件做实时校验,用户填写内容时按钮状态不会同步更新
  • 提交后的5秒禁用没有配套的定时恢复逻辑,禁用后不会自动变回可用状态,也没有处理页面刷新后冷却期的状态保持
  • textarea默认值带前置空格,会干扰空值判断,即使用户没有输入内容,value也不是空字符串
修正方案

核心调整逻辑:

  • 把表单校验逻辑抽成独立公共函数,统一判断所有字段的有效性(含邮箱格式校验、空值trim处理)
  • 给所有输入字段绑定input事件,用户输入时实时更新按钮状态
  • 页面加载时自动检查是否处于提交后的5秒冷却期,冷却期内保持按钮禁用,到点自动恢复
  • 提交事件中先做全量校验,校验通过才执行提交、触发5秒禁用逻辑
  • 修正textarea默认值的前置空格问题,避免非用户输入的内容干扰空值判断

修正后的完整JS代码如下:

const button = document.querySelector("#buttonSubmit");
const form = document.getElementById("contactForm");
const buttonExpirationDataKey = 'button-disabled-expiration';
const fields = ["name", "email", "body"];
// 邮箱格式校验正则
const emailReg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

// 全字段校验函数,返回是否所有字段均有效
function checkFormValid() {
  // 先判断是否处于提交后的禁用冷却期
  const expiration = localStorage.getItem(buttonExpirationDataKey);
  if (expiration && new Date(expiration).getTime() > Date.now()) {
    return false;
  }
  // 逐字段校验
  for (const field of fields) {
    const val = form[field].value.trim();
    // 空值直接判定无效
    if (!val) return false;
    // 邮箱字段额外校验格式
    if (field === 'email' && !emailReg.test(val)) return false;
  }
  return true;
}

// 更新按钮状态
function updateButtonStatus() {
  button.disabled = !checkFormValid();
}

// 所有输入项绑定实时校验事件
fields.forEach(field => {
  form[field].addEventListener('input', updateButtonStatus);
});

// 页面加载时初始化状态
window.addEventListener('load', () => {
  updateButtonStatus();
  const expiration = localStorage.getItem(buttonExpirationDataKey);
  if (expiration) {
    const remainTime = new Date(expiration).getTime() - Date.now();
    if (remainTime > 0) {
      // 剩余冷却时间内保持禁用,到点自动恢复
      setTimeout(() => {
        localStorage.removeItem(buttonExpirationDataKey);
        updateButtonStatus();
      }, remainTime);
    } else {
      localStorage.removeItem(buttonExpirationDataKey);
    }
  }
});

// 表单提交事件逻辑
form.addEventListener("submit", (e) => {
  // 提交前再做一次校验,不通过直接拦截提交
  if (!checkFormValid()) {
    e.preventDefault();
    return;
  }
  // 校验通过,设置5秒禁用
  button.disabled = true;
  const expirationTime = 5 * 1000;
  const expirationDate = new Date(Date.now() + expirationTime);
  localStorage.setItem(buttonExpirationDataKey, expirationDate);
  // 定时器到点恢复按钮状态
  setTimeout(() => {
    localStorage.removeItem(buttonExpirationDataKey);
    updateButtonStatus();
  }, expirationTime);
});

建议将textarea的默认值修改为不带前置空格的形式,或直接使用placeholder属性做输入提示,避免默认内容干扰校验:

<textarea name="body" id="message" rows="5" placeholder="Enter your message"></textarea>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 10:21:23