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

如何使用JavaScript/jQuery控制表单提交按钮的禁用/启用状态

Laravel表单防重复提交按钮逻辑异常修复

问题背景

已完成Blade表单页面与后端控制器字段校验,预期实现交互逻辑:

  • 点击提交按钮时检查所有输入项填写状态
  • 若存在任意字段缺失:按钮保持启用状态,表单提交后由后端返回This field is required错误提示,展示在对应输入框旁
  • 若所有字段均已填写:点击提交后按钮立即禁用,将禁用过期状态存入localStorage,到期自动恢复启用,防止重复提交

当前异常表现:即使用户未填写任何表单输入项,点击提交按钮时仍会被错误禁用,无法满足需求。


原有代码

Blade模板代码

<form method="post" action="someURL" id="register">
<input type="text" name="name" id="name" />
<div class="error">{{ $errors->first('name') }}</div>
<input type="email" name="email" id="email"/>
<div class="error">{{ $errors->first('email') }}</div>
<textarea name="body" id="message"> Enter your message here</textarea>
<div class="error">{{ $errors->first('message') }}</div>
<input type="submit" id="btnSubmit" disabled />
</form>


<script>
const button = document.querySelector("#btnSubmit");
const buttonExpirationDataKey = 'button-disabled-expiration';

let startButtonStateCheck = () => {
  button.dataset.interval = setInterval(updateButtonState, 1000);
}

let updateButtonState = () => {
  let expirationDate = new Date(button.dataset.enabledAt);
  
  if (expirationDate < new Date()) {
    button.disabled = false;
    clearInterval(button.dataset.interval);
  } else {
    button.disabled = true;
  }
}

let buttonDisableExpiration = localStorage.getItem(buttonExpirationDataKey);
if (!buttonDisableExpiration) {
  // 本地存储无按钮状态记录,启用按钮
  button.disabled = false;
} else {
  // 本地存储存在按钮状态记录,每秒检查过期时间,到期后重新启用按钮
  button.dataset.enabledAt = buttonDisableExpiration;
    updateButtonState();
  startButtonStateCheck();
}

button.addEventListener("click", () => {
 var form = document.getElementById("register");
  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 = false;
          }
          else{
           button.disabled = true;
           let now = new Date();
           let expirationTime = 1000 * 10; 
           let expirationDate = new Date(now.getTime() + expirationTime);
           localStorage.setItem(buttonExpirationDataKey, expirationDate);
            button.dataset.enabledAt = expirationDate;
            startButtonStateCheck();
          }
       }
});

</script>

后端控制器校验代码

$data = request()->validate([
         'name' => 'required',
         'email'   => 'required|email',
         'body' =>  'required',
      ]);

错误原因

  1. 字段校验逻辑顺序错误:遍历字段时逐个判断,只要遍历到任意一个非空字段就立刻触发按钮禁用,不会等待所有字段校验完成
  2. 文本域默认值干扰:<textarea>标签内直接写入了提示文本,导致页面加载后body字段默认值不为空,首次遍历到该字段时就会触发禁用
  3. 未处理空格场景:用户输入全空格内容时会被判定为已填写,绕过非空判断
  4. 定时器重复创建:多次点击按钮会重复调用setInterval生成多个并行定时器,造成资源浪费

修正代码

  1. 首先修改文本域,将内置提示文本移到placeholder属性,避免默认值干扰校验:
<textarea name="body" id="message" placeholder="Enter your message here"></textarea>
  1. 替换按钮点击事件内的逻辑,先完成全字段校验再统一处理按钮状态:
button.addEventListener("click", () => {
  const form = document.getElementById("register");
  const fields = ["name", "email", "body"];
  // 校验所有字段是否均已填写(自动去除首尾空格)
  const isAllFilled = fields.every(field => form[field].value.trim() !== "");

  if (!isAllFilled) {
    // 存在未填写字段,保持按钮启用,等待后端返回校验错误
    button.disabled = false;
    return;
  }

  // 所有字段填写完成,执行防重复提交禁用逻辑
  button.disabled = true;
  const now = new Date();
  const expirationTime = 1000 * 10; 
  const expirationDate = new Date(now.getTime() + expirationTime);
  localStorage.setItem(buttonExpirationDataKey, expirationDate);
  button.dataset.enabledAt = expirationDate;
  // 清除已有定时器,避免重复创建
  if (button.dataset.interval) {
    clearInterval(button.dataset.interval);
  }
  startButtonStateCheck();
});

其余页面初始化、定时器状态更新逻辑无需修改,替换后即可符合预期交互要求。

内容的提问来源于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 18:57:35