Form 是什么
Vant 的 Form 组件是一个 表单容器,用于管理一组 Field 的校验和提交。真正的输入框是 van-field,Form 负责:
- 统一管理所有字段的校验规则
- 一键触发校验 / 提交
- 自动显示错误提示
最小可用示例
<template>
<van-form @submit="onSubmit">
<van-field
v-model="username"
name="username"
label="用户名"
placeholder="请输入用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
<van-field
v-model="password"
name="password"
type="password"
label="密码"
placeholder="请输入密码"
:rules="[
{ required: true, message: '请填写密码' },
{ min: 6, message: '密码至少 6 位' },
]"
/>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit">提交</van-button>
</div>
</van-form>
</template>
<script setup>
import { ref } from "vue";
import { showToast } from "vant";
const username = ref("");
const password = ref("");
const onSubmit = (values) => {
console.log("表单数据:", values);
showToast("提交成功");
};
</script>
校验规则 rules
每个 Field 可以通过 :rules 传入一个规则数组,常用规则:
// 必填
{ required: true, message: '此项必填' }
// 最小长度
{ min: 6, message: '至少 6 个字符' }
// 最大长度
{ max: 20, message: '最多 20 个字符' }
// 正则
{ pattern: /^1\d{10}$/, message: '请输入正确手机号' }
// 自定义校验函数
{
validator: (value) => value.length >= 6,
message: '密码至少 6 位',
}
// 异步校验
{
validator: async (value) => {
await new Promise((r) => setTimeout(r, 500));
return value !== 'admin';
},
message: '用户名已存在',
}
完整的登录表单示例
<template>
<van-form @submit="onSubmit">
<van-cell-group inset title="账号登录">
<van-field
v-model="form.phone"
name="phone"
label="手机号"
type="tel"
maxlength="11"
placeholder="请输入 11 位手机号"
:rules="[
{ required: true, message: '手机号不能为空' },
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确' },
]"
/>
<van-field
v-model="form.code"
name="code"
label="验证码"
type="tel"
maxlength="6"
placeholder="请输入 6 位验证码"
:rules="[
{ required: true, message: '验证码不能为空' },
{ pattern: /^\d{6}$/, message: '验证码格式不正确' },
]"
>
<template #button>
<van-button
size="small"
type="primary"
:disabled="countdown > 0"
@click="sendCode"
>{{ countdown > 0 ? `${countdown}s 后重发` : '获取验证码' }}
</van-button>
</template>
</van-field>
</van-cell-group>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit" :loading="loading">
登录
</van-button>
</div>
</van-form>
</template>
<script setup>
import { reactive, ref } from "vue";
import { showToast } from "vant";
const form = reactive({ phone: "", code: "" });
const loading = ref(false);
const countdown = ref(0);
const sendCode = () => {
if (countdown.value > 0) return;
countdown.value = 60;
const timer = setInterval(() => {
countdown.value--;
if (countdown.value <= 0) clearInterval(timer);
}, 1000);
showToast("验证码已发送");
};
const onSubmit = async (values) => {
loading.value = true;
try {
await new Promise((r) => setTimeout(r, 1000));
showToast("登录成功");
} catch (e) {
showToast("登录失败");
} finally {
loading.value = false;
}
};
</script>
常见踩坑
- Field 必须有 name 属性,否则 Form 无法识别和校验它
- rules 里的自定义 validator 返回值:true 表示通过,false 表示不通过
- Form 的 submit 通过 native-type="submit" 触发,不要自己在按钮上加 @click
- 异步 validator 要在 async 函数里 return,Vant 会自动 await