npm package: @mgcloud/vite-plugin-auto-prevent-form-submit
Description: 自动为 Element UI/Plus 的 el-form 标签添加 @submit.prevent，防止表单默认提交行为的 Vite 插件
Author: wudi
Latest version: 0.0.1

# 🚀 @mgcloud/vite-plugin-auto-prevent-form-submit

[![npm version](https://img.shields.io/npm/v/@mgcloud/vite-plugin-auto-prevent-form-submit?logo=npm)](https://www.npmjs.com/package/@mgcloud/vite-plugin-auto-prevent-form-submit)

一个 Vite 插件，自动为 Element UI/Plus 的 `<el-form>` 标签添加 `@submit.prevent`（Vue 3）或 `@submit.native.prevent`（Vue 2），防止表单默认提交行为。

## ✨ 特性

- 🎯 **自动处理**：无需手动为每个表单添加 `@submit.prevent`
- 🔧 **智能识别**：自动跳过已有 `@submit` 处理器的表单
- 🚀 **高性能**：使用正则表达式和缓存的 picomatch 匹配器，处理速度快
- 🎨 **灵活配置**：支持自定义文件过滤、Vue 版本选择等
- 💪 **TypeScript 支持**：完整的类型定义
- ⚡ **依赖**：仅依赖 `picomatch` 用于 glob 模式匹配

## 📦 安装

```bash
pnpm add -D @mgcloud/vite-plugin-auto-prevent-form-submit
```

## 🔨 使用

### 基础用法

在 `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
<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
<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 示例

```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
<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`/`exclude` 或 `filter` 函数判断是否处理文件
2. **智能检测**：使用正则表达式检测 `<el-form>` 标签
3. **跳过已处理**：如果表单已有任何 `@submit` 处理器（如 `@submit`、`@submit.prevent`、`@submit.native.prevent` 等），则跳过
4. **添加处理器**：
   - Vue 3：添加 `@submit.prevent`
   - Vue 2：添加 `@submit.native.prevent`
5. **保留原有属性**：转换过程中保留所有原有的表单属性和格式

## 📝 注意事项

### ✅ 会被处理的情况

```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
<!-- 已有 @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
<!-- 手动添加，容易遗漏 -->
<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 项目并修改正则表达式。

## 📜 License

[MIT](../../LICENSE) License &copy; 2023-PRESENT [wudi](https://github.com/WuChenDi)