返回

Element Plus 表单校验常见写法

记录 Element Plus 的 el-form 校验要点,包括 model 与 prop 对齐、常用 rules、提交前验证、重置表单以及编辑弹窗的清理方式。

后台项目里,新增和编辑弹窗大多离不开 el-form。表单校验看起来简单,真正容易出问题的地方通常是 modelproprules 三者没有对齐,或者弹窗复用后遗留了上一次的校验状态。

最小可用的表单结构

el-form:model 指向表单数据;每个 el-form-itemprop 必须与数据字段、规则字段一致。下面的 nameemail 三处都对应同一个字段名。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<script setup lang="ts">
import { reactive, ref } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'

interface UserForm {
  name: string
  email: string
}

const formRef = ref<FormInstance>()
const form = reactive<UserForm>({
  name: '',
  email: '',
})

const rules: FormRules<UserForm> = {
  name: [
    { required: true, message: '请输入用户名', trigger: 'blur' },
    { min: 2, max: 20, message: '长度为 2 到 20 个字符', trigger: 'blur' },
  ],
  email: [
    { required: true, message: '请输入邮箱', trigger: 'blur' },
    { type: 'email', message: '邮箱格式不正确', trigger: ['blur', 'change'] },
  ],
}
</script>

<template>
  <el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
    <el-form-item label="用户名" prop="name">
      <el-input v-model="form.name" placeholder="请输入用户名" />
    </el-form-item>

    <el-form-item label="邮箱" prop="email">
      <el-input v-model="form.email" placeholder="name@example.com" />
    </el-form-item>
  </el-form>
</template>

如果 prop="userName",而 form 写的是 name,规则不会生效。这是排查校验问题时最先该看的地方。

提交前统一校验

不要只依赖输入框失焦时的提示。提交按钮仍然要执行一次 validate,确认所有字段都通过后再调接口。

1
2
3
4
5
6
7
const submit = async () => {
  const valid = await formRef.value?.validate().catch(() => false)

  if (!valid) return

  await saveUser({ ...form })
}

validate 校验失败时会抛出异常,所以这里用 catch 转成 false。通过后再复制一份数据提交,可以避免接口函数直接修改响应式对象。

编辑弹窗要清掉旧提示

一个弹窗既用于新增又用于编辑时,切换数据后经常会看到上一位用户留下的红色提示。可以在弹窗打开后清掉校验状态。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import { nextTick } from 'vue'

const openCreate = async () => {
  Object.assign(form, { name: '', email: '' })
  await nextTick()
  formRef.value?.clearValidate()
}

const openEdit = async (user: UserForm) => {
  Object.assign(form, user)
  await nextTick()
  formRef.value?.clearValidate()
}

如果表单初始值始终不变,也可以使用 formRef.value?.resetFields()。它会把数据还原为组件初始化时的值,更适合单纯的“清空新增表单”。

只校验一个字段

分步表单或者发送验证码前,往往只需要校验邮箱或手机号。这时用 validateField,不必校验整张表单。

1
2
3
4
5
6
const sendCode = async () => {
  const valid = await formRef.value?.validateField('email').catch(() => false)

  if (!valid) return
  await requestEmailCode(form.email)
}

自定义规则适合什么场景

确认密码、日期范围、业务编号唯一性等情况,内置规则不够用时可以增加 validator。校验函数只负责给出结果,不要在里面请求大量无关数据。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const passwordForm = reactive({
  password: '',
  confirmPassword: '',
})

const validateConfirmPassword = (
  _rule: unknown,
  value: string,
  callback: (error?: Error) => void,
) => {
  if (value !== passwordForm.password) {
    callback(new Error('两次输入的密码不一致'))
    return
  }

  callback()
}

小结

我现在处理 Element Plus 表单时,先保证字段名完全对齐,再把提交校验、弹窗清理和局部校验补齐。这样新增、编辑、分步操作放在同一个页面里,表单状态也不会越用越乱。

使用 Hugo 构建
主题 StackJimmy 设计