Skip to content

🚀 @mgcloud/vite-plugin-auto-prevent-form-submit

NPM

npm version

npm downloads

一个 Vite 插件,自动为 Element UI/Plus 的 <el-form> 标签添加 @submit.prevent(Vue 3)或 @submit.native.prevent(Vue 2),防止表单默认提交行为。

✨ 特性

  • 🎯 自动处理:无需手动为每个表单添加 @submit.prevent
  • 🔧 智能识别:自动跳过已有 @submit 处理器的表单
  • 🚀 高性能:使用正则表达式和缓存的 picomatch 匹配器,处理速度快
  • 🎨 灵活配置:支持自定义文件过滤、Vue 版本选择等
  • 💪 TypeScript 支持:完整的类型定义
  • 依赖:仅依赖 picomatch 用于 glob 模式匹配

📦 安装

pnpm
bash
pnpm add -D @mgcloud/vite-plugin-auto-prevent-form-submit

🔨 使用

基础用法

vite.config.ts 中配置插件:

vite.config.ts
typescript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import autoPreventFormSubmit from '@mgcloud/vite-plugin-auto-prevent-form-submit'

export default defineConfig({
  plugins: [
    vue(),
    autoPreventFormSubmit()
  ]
})

Vue 3 示例

转换前:

vue
vue
<template>
  <el-form :model="form" :rules="rules">
    <el-form-item label="用户名" prop="username">
      <el-input v-model="form.username"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
    </el-form-item>
  </el-form>
</template>

转换后:

vue
vue
<template>
  <el-form :model="form" :rules="rules" @submit.prevent>
    <el-form-item label="用户名" prop="username">
      <el-input v-model="form.username"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
    </el-form-item>
  </el-form>
</template>

Vue 2 示例

vite.config.ts
typescript
// vite.config.ts
import vue from '@vitejs/plugin-vue2'
import autoPreventFormSubmit from '@mgcloud/vite-plugin-auto-prevent-form-submit'

export default defineConfig({
  plugins: [
    vue(),
    autoPreventFormSubmit({
      vueVersion: 2  // 使用 Vue 2 模式
    })
  ]
})

转换后:

vue
vue
<template>
  <el-form :model="form" :rules="rules" @submit.native.prevent>
    <!-- form content -->
  </el-form>
</template>

⚙️ 配置选项

AutoPreventFormSubmitOptions

typescript
interface AutoPreventFormSubmitOptions {
  /**
   * Glob 模式匹配要处理的文件
   * @default ['**\/*.vue']
   */
  include?: string[]

  /**
   * Glob 模式匹配要排除的文件
   * @default []
   */
  exclude?: string[]

  /**
   * 自定义过滤函数,用于判断文件是否需要处理
   * 如果提供此函数,将覆盖 include/exclude 配置
   * @param id - 文件路径
   * @returns true 表示需要处理该文件
   */
  filter?: ((id: string) => boolean) | null

  /**
   * 是否启用插件
   * @default true
   */
  enabled?: boolean

  /**
   * Vue 版本(2 或 3)
   * - Vue 3: 添加 @submit.prevent
   * - Vue 2: 添加 @submit.native.prevent
   * @default 3
   */
  vueVersion?: 2 | 3
}

配置示例

1. 自定义文件匹配

typescript
autoPreventFormSubmit({
  include: ['src/**/*.vue', 'components/**/*.vue'],
  exclude: ['**/*.spec.vue', '**/*.test.vue', 'src/test/**/*.vue']
})

2. 使用自定义过滤函数

typescript
autoPreventFormSubmit({
  filter: (id: string) => {
    // 只处理 components 和 views 目录,排除 admin 目录
    return (id.includes('/components/') || id.includes('/views/')) && !id.includes('/admin/')
  }
})

3. Vue 2 项目配置

typescript
autoPreventFormSubmit({
  vueVersion: 2,
  include: ['src/**/*.vue']
})

4. 条件启用

typescript
autoPreventFormSubmit({
  enabled: process.env.NODE_ENV !== 'production'  // 仅在开发环境启用
})

🎯 工作原理

  1. 文件过滤:根据配置的 include/excludefilter 函数判断是否处理文件
  2. 智能检测:使用正则表达式检测 <el-form> 标签
  3. 跳过已处理:如果表单已有任何 @submit 处理器(如 @submit@submit.prevent@submit.native.prevent 等),则跳过
  4. 添加处理器
    • Vue 3:添加 @submit.prevent
    • Vue 2:添加 @submit.native.prevent
  5. 保留原有属性:转换过程中保留所有原有的表单属性和格式

📝 注意事项

✅ 会被处理的情况

vue
vue
<!-- 基础表单 -->
<el-form :model="form">
...
</el-form>

<!-- 带多个属性的表单 -->
<el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
...
</el-form>

<!-- 自闭合表单 -->
<el-form :model="form" />

<!-- 多行表单 -->
<el-form
  :model="form"
  :rules="rules"
  ref="formRef"
>
...
</el-form>

❌ 不会被处理的情况

vue
vue
<!-- 已有 @submit 处理器 -->
<el-form @submit="handleSubmit">
...
</el-form>

<!-- 已有 @submit.prevent -->
<el-form @submit.prevent>
...
</el-form>

<!-- 已有 @submit.native.prevent -->
<el-form @submit.native.prevent>
...
</el-form>

<!-- 已有任何 @submit 修饰符 -->
<el-form @submit.stop="handleSubmit">
...
</el-form>

<!-- 非 el-form 标签 -->
<el-form-item>
...
</el-form-item>

<el-form-dialog>
...
</el-form-dialog>

🚀 性能

  • 快速处理:使用正则表达式,处理 100 个表单通常在 100ms 内完成
  • 🎯 智能跳过:不包含 <el-form> 的文件会被快速跳过
  • 💾 缓存优化:picomatch 匹配器会被缓存,重复匹配性能更好
  • 📦 轻量级:核心代码简洁,不会显著增加构建时间

🤔 为什么需要这个插件?

在使用 Element UI/Plus 开发表单时,如果不阻止表单的默认提交行为,按下回车键会触发页面刷新。通常我们需要手动为每个 <el-form> 添加 @submit.prevent

vue
vue
<!-- 手动添加,容易遗漏 -->
<el-form @submit.prevent :model="form">
  <!-- form content -->
</el-form>

这个插件可以:

  • ✨ 自动添加,无需手动处理
  • 🛡️ 避免遗漏导致的页面刷新问题
  • 🎯 智能识别已有处理器,不会重复添加
  • 🔧 统一管理,提高代码一致性

🔍 常见问题

Q: 插件会修改已有的 @submit 处理器吗?

A: 不会。插件会检测表单是否已有任何 @submit 相关的处理器,如果有则完全跳过该表单。

Q: 支持 TypeScript 吗?

A: 是的,插件提供了完整的 TypeScript 类型定义。

Q: 会影响构建性能吗?

A: 影响很小。插件使用高效的正则表达式和缓存机制,通常不会显著增加构建时间。

Q: 可以在生产环境禁用吗?

A: 可以,使用 enabled: false 或根据环境变量条件启用:

typescript
autoPreventFormSubmit({
  enabled: process.env.NODE_ENV !== 'production'
})

Q: 支持 Element Plus 和 Element UI 吗?

A: 是的,两者都支持。插件只处理 <el-form> 标签,与具体的组件库版本无关。

Q: 可以自定义要处理的标签吗?

A: 目前插件专门针对 <el-form> 标签设计。如果需要处理其他标签,可以 fork 项目并修改正则表达式。