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

Vue3实现表单内容变更时启用/禁用提交按钮的最优方案

Vue3大型表单提交按钮高效控制方案

核心需求

  • 表单未变更时,提交按钮禁用
  • 表单内容修改后,按钮启用
  • 用户将内容恢复为初始值,按钮重新禁用
  • 适配大型表单,避免逐个字段监听或低效深度监听

高效实现思路

  1. 保存初始快照:组件挂载时,用structuredClone深拷贝初始表单数据作为对比基准
  2. 统一监听输入事件:利用表单的input事件冒泡特性,监听所有表单元素的输入操作,无需逐个字段绑定事件
  3. 按需对比数据:仅在用户输入时触发数据对比,更新按钮禁用状态,减少不必要的计算
  4. 更新快照(可选):表单提交成功后,将当前数据更新为新的初始快照,适配后续编辑场景

完整可运行代码

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Home</title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width" />
  <script src="https://unpkg.com/vue@3/dist/vue.global.js" defer></script>
  <style>
    .submit-btn {
      color: #fff;
      background: #000;
      padding: 24px;
    }

    .submit-btn[disabled] {
      color: #fff;
      background: #999;
    }
  </style>
</head>
<body>
  <div id="app">
    <form @submit="onSubmit" @input="checkFormChanged" id="test-form">

      <label for="first_name">First Name</label>
      <input id="first_name" 
        type="text"
        v-model="formData.first_name"
      >

      <label for="email">Email</label>
      <input id="email" 
        type="email"
        v-model="formData.email"
      >
      <!-- 大型表单可直接扩展更多字段 -->

      <input type="submit" 
        value="save" 
        class="submit-btn"
        :disabled="!isFormChanged"
      >
    </form>
  </div>

  <script type="module">
    Vue.createApp({
      name: 'form_app',
      data() {
        return {
          formData: {
            first_name: 'john',
            email: 'john@gmail.com'
            // 新增字段直接添加到这里即可
          },
          initialFormData: null,
          isFormChanged: false
        }
      },
      mounted() {
        // 挂载时保存初始数据快照
        this.initialFormData = structuredClone(this.formData);
        // 初始化检查按钮状态
        this.checkFormChanged();
      },
      methods: {
        checkFormChanged() {
          // 简单结构用JSON.stringify对比,复杂结构换自定义深对比
          this.isFormChanged = JSON.stringify(this.formData) !== JSON.stringify(this.initialFormData);
          
          // 若表单包含嵌套对象、数组等复杂结构,启用以下自定义深对比函数
          // this.isFormChanged = !this.deepEqual(this.formData, this.initialFormData);
        },
        deepEqual(a, b) {
          // 自定义深对比逻辑,处理复杂数据结构
          if (a === b) return true;
          if (a == null || typeof a !== 'object' || b == null || typeof b !== 'object') return false;
          const keysA = Object.keys(a), keysB = Object.keys(b);
          if (keysA.length !== keysB.length) return false;
          for (const key of keysA) {
            if (!keysB.includes(key) || !this.deepEqual(a[key], b[key])) return false;
          }
          return true;
        },
        onSubmit(e) {
          e.preventDefault();
          console.log('form submitted', this.formData);
          // 提交成功后更新初始快照,适配后续编辑
          this.initialFormData = structuredClone(this.formData);
          this.checkFormChanged();
        }
      }
    }).mount('#app')
  </script>
</body>
</html>

方案优势

  • 性能高效:仅在用户输入时触发对比,避免响应式深度监听的持续性能开销
  • 扩展性强:新增表单字段无需修改监听逻辑,直接添加到formData即可
  • 代码简洁:利用事件冒泡减少冗余代码,大型表单下维护成本低

注意事项

  • JSON.stringify对比适合结构简单的表单,若表单包含undefined、函数或键顺序不固定的对象,建议使用自定义deepEqual函数
  • structuredClone是ES2022原生API,支持绝大多数现代浏览器,需兼容旧浏览器可改用自定义深拷贝函数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 10:55:50