Close
升级到 Vue 3 | Vue 2 EOL

表单验证

基本示例

表单验证由浏览器原生支持,但有时不同的浏览器会以不同的方式处理,这使得依赖它变得有点棘手。即使验证完美支持,也可能需要自定义验证,而更手动、基于 Vue 的解决方案可能更合适。让我们从一个简单的例子开始。

给定一个包含三个字段的表单,使两个字段为必填。让我们先看看 HTML

<form
id="app"
@submit="checkForm"
action="https://vuejs.net.cn/"
method="post"
>

<p v-if="errors.length">
<b>Please correct the following error(s):</b>
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</p>

<p>
<label for="name">Name</label>
<input
id="name"
v-model="name"
type="text"
name="name"
>
</p>

<p>
<label for="age">Age</label>
<input
id="age"
v-model="age"
type="number"
name="age"
min="0"
>
</p>

<p>
<label for="movie">Favorite Movie</label>
<select
id="movie"
v-model="movie"
name="movie"
>
<option>Star Wars</option>
<option>Vanilla Sky</option>
<option>Atomic Blonde</option>
</select>
</p>

<p>
<input
type="submit"
value="Submit"
>
</p>

</form>

让我们从上到下解释。<form> 标签有一个 ID,我们将用于 Vue 组件。有一个提交处理程序,您将在稍后看到,action 是一个临时 URL,它将指向服务器上的某个真实位置(当然,您在那里有备份服务器端验证)。

在它下面是一个段落,它根据错误状态显示或隐藏自身。这将在表单顶部呈现一个简单的错误列表。还要注意,我们在提交时触发验证,而不是在每个字段修改时触发。

最后要注意的是,三个字段中的每一个都对应一个 v-model,用于将它们连接到我们在 JavaScript 中使用的值。现在让我们看看 JavaScript。

const app = new Vue({
el: '#app',
data: {
errors: [],
name: null,
age: null,
movie: null
},
methods:{
checkForm: function (e) {
if (this.name && this.age) {
return true;
}

this.errors = [];

if (!this.name) {
this.errors.push('Name required.');
}
if (!this.age) {
this.errors.push('Age required.');
}

e.preventDefault();
}
}
})

相当短小精悍。我们定义一个数组来保存错误,并为三个表单字段设置 null 值。checkForm 逻辑(记住它在提交时运行)只检查 name 和 age,因为 movie 是可选的。如果它们为空,我们将检查每个字段并为每个字段设置一个特定的错误。就这样。您可以运行下面的演示。不要忘记,在成功提交后,它将 POST 到一个临时 URL。

查看 CodePen 上 Raymond Camden (@cfjedimaster) 的 表单验证 1

使用自定义验证

在第二个示例中,第二个文本字段 (age) 被切换为 email,它将使用一些自定义逻辑进行验证。代码取自 StackOverflow 问题 如何在 JavaScript 中验证电子邮件地址?。这是一个很棒的问题,因为它让您最激烈的 Facebook 政治/宗教争论看起来像是一场关于谁酿造的啤酒最好的轻微分歧。说真的,太疯狂了。以下是 HTML,尽管它与第一个示例非常接近。

<form
id="app"
@submit="checkForm"
action="https://vuejs.net.cn/"
method="post"
novalidate="true"
>

<p v-if="errors.length">
<b>Please correct the following error(s):</b>
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</p>

<p>
<label for="name">Name</label>
<input
id="name"
v-model="name"
type="text"
name="name"
>
</p>

<p>
<label for="email">Email</label>
<input
id="email"
v-model="email"
type="email"
name="email"
>
</p>

<p>
<label for="movie">Favorite Movie</label>
<select
id="movie"
v-model="movie"
name="movie"
>
<option>Star Wars</option>
<option>Vanilla Sky</option>
<option>Atomic Blonde</option>
</select>
</p>

<p>
<input
type="submit"
value="Submit"
>
</p>

</form>

虽然这里的更改很小,但请注意顶部的 novalidate="true"。这很重要,因为浏览器会在 type="email" 时尝试验证字段中的电子邮件地址。坦率地说,在这种情况下,信任浏览器可能更有意义,但由于我们想要一个使用自定义验证的示例,因此我们禁用了它。以下是更新后的 JavaScript。

const app = new Vue({
el: '#app',
data: {
errors: [],
name: null,
email: null,
movie: null
},
methods: {
checkForm: function (e) {
this.errors = [];

if (!this.name) {
this.errors.push("Name required.");
}
if (!this.email) {
this.errors.push('Email required.');
} else if (!this.validEmail(this.email)) {
this.errors.push('Valid email required.');
}

if (!this.errors.length) {
return true;
}

e.preventDefault();
},
validEmail: function (email) {
var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
}
})

如您所见,我们添加了 validEmail 作为一种新方法,它只是从 checkForm 中调用。您可以在此处玩这个示例

查看 CodePen 上 Raymond Camden (@cfjedimaster) 的 表单验证 2

另一个自定义验证示例

在第三个示例中,我们构建了一些您可能在调查应用程序中看到过的东西。用户被要求为新星际驱逐舰模型的一组功能分配“预算”。总计必须等于 100。首先,是 HTML。

<form
id="app"
@submit="checkForm"
action="https://vuejs.net.cn/"
method="post"
novalidate="true"
>

<p v-if="errors.length">
<b>Please correct the following error(s):</b>
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</p>

<p>
Given a budget of 100 dollars, indicate how much
you would spend on the following features for the
next generation Star Destroyer. Your total must sum up to 100.
</p>

<p>
<input
v-model.number="weapons"
type="number"
name="weapons"
> Weapons <br/>
<input
v-model.number="shields"
type="number"
name="shields"
> Shields <br/>
<input
v-model.number="coffee"
type="number"
name="coffee"
> Coffee <br/>
<input
v-model.number="ac"
type="number"
name="ac"
> Air Conditioning <br/>
<input
v-model.number="mousedroids"
type="number"
name="mousedroids"
> Mouse Droids <br/>
</p>

<p>
Current Total: {{total}}
</p>

<p>
<input
type="submit"
value="Submit"
>
</p>

</form>

注意涵盖五种不同功能的一组输入。注意 v-model 属性中添加的 .number。这告诉 Vue 在您使用它时将值转换为数字。但是,此功能存在一个错误,即当值为空时,它会变回字符串。您将在下面看到解决方法。为了让用户更容易操作,我们还在下面添加了当前总计,以便他们可以实时查看其总计。现在让我们看看 JavaScript。

const app = new Vue({
el: '#app',
data:{
errors: [],
weapons: 0,
shields: 0,
coffee: 0,
ac: 0,
mousedroids: 0
},
computed: {
total: function () {
// must parse because Vue turns empty value to string
return Number(this.weapons) +
Number(this.shields) +
Number(this.coffee) +
Number(this.ac+this.mousedroids);
}
},
methods:{
checkForm: function (e) {
this.errors = [];

if (this.total != 100) {
this.errors.push('Total must be 100!');
}

if (!this.errors.length) {
return true;
}

e.preventDefault();
}
}
})

我们将总值设置为一个计算值,除了我遇到的那个错误之外,设置起来很简单。我的 checkForm 方法现在只需要查看总计是否为 100,仅此而已。您可以在此处玩这个示例

查看 CodePen 上 Raymond Camden (@cfjedimaster) 的 表单验证 3

服务器端验证

在我的最后一个示例中,我们构建了一些利用 Ajax 在服务器上进行验证的东西。该表单将要求您命名一个新产品,然后检查以确保该名称是唯一的。我们编写了一个快速的 Netlify 无服务器操作来执行验证。虽然它并不十分重要,但以下是逻辑

exports.handler = async (event, context) => {

const badNames = ['vista', 'empire', 'mbp'];
const name = event.queryStringParameters.name;

if (badNames.includes(name)) {
return {
statusCode: 400,
body: JSON.stringify({error: 'Invalid name passed.'})
}
}

return {
statusCode: 204
}

}

基本上除了“vista”、“empire”和“mbp”之外的任何名称都是可以接受的。好的,让我们看看表单。

<form
id="app"
@submit="checkForm"
method="post"
>

<p v-if="errors.length">
<b>Please correct the following error(s):</b>
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</p>

<p>
<label for="name">New Product Name: </label>
<input
id="name"
v-model="name"
type="text"
name="name"
>
</p>

<p>
<input
type="submit"
value="Submit"
>
</p>

</form>

这里没有什么特别之处。所以让我们继续 JavaScript。

const apiUrl = 'https://vuecookbook.netlify.app/.netlify/functions/product-name?name=';

const app = new Vue({
el: '#app',
data: {
errors: [],
name: ''
},
methods:{
checkForm: function (e) {
e.preventDefault();

this.errors = [];

if (this.name === '') {
this.errors.push('Product name is required.');
} else {
fetch(apiUrl + encodeURIComponent(this.name))
.then(async res => {
if (res.status === 204) {
alert('OK');
} else if (res.status === 400) {
let errorResponse = await res.json();
this.errors.push(errorResponse.error);
}
});
}
}
}
})

我们从一个表示在 OpenWhisk 上运行的 API 的 URL 的变量开始。现在看看 checkForm。在这个版本中,我们始终阻止表单提交(顺便说一句,这也可以在 HTML 中使用 Vue 完成)。您可以看到对 this.name 为空的简单检查,然后我们访问 API。如果不好,我们会像以前一样添加一个错误。如果很好,现在我们什么也不做(只是一个警报),但您可以将用户导航到一个带有产品名称的 URL 的新页面,或者执行其他操作。您可以在下面运行此演示

查看 CodePen 上 Raymond Camden (@cfjedimaster) 的 表单验证 4

替代模式

虽然本菜谱条目侧重于“手动”进行表单验证,但当然,也有一些很棒的 Vue 库可以为您处理很多事情。切换到预打包库可能会影响应用程序的最终大小,但好处可能是巨大的。您拥有经过大量测试并且定期更新的代码。一些 Vue 表单验证库的示例包括