VueJS 表单构建指南(全)
原文:
zh.annas-archive.org/md5/89D4502ECBF31F487E1AF228404A6AC0
译者:飞龙
前言
Vue.js 是世界领先和增长最快的前端开发框架之一。其平缓的学习曲线和充满活力和乐于助人的社区使其成为许多新开发人员寻求利用前端框架的力量的不二选择。此外,其灵活性和强大性使其成为高级开发人员和公司选择将其作为强大、动态和精简应用程序和网站的主要工具。
在使用 Vue.js 构建表单中,我们将探索前端开发的一个特定部分——表单。我们将一起旅行,从创建最基本的表单,一直到理解完全动态、基于模式的表单是如何工作的。
这本书是为谁准备的
使用 Vue.js 构建表单旨在面向具有 Vue.js 框架基本理解的前端开发人员,他们想要了解如何更好地创建强大且可重用的表单。
本书涵盖的内容
第一章,“设置演示项目”,将指导您设置项目的基础,我们将在整本书中构建该项目。建议您按照章节的顺序学习本书,因为它们是基于前面章节学习的概念构建的。但是,如果您想要跳过,每章的完成代码将在每章的开头提供。
第二章,“最简单的形式中的表单”,展示了构建基本网络表单的基础知识,以及将输入连接到应用程序状态的过程。您还将了解提交表单的基础知识,并使用 Axios 库进行异步调用后端。
第三章,“创建可重用的表单组件”,将教您如何将表单分解为可以在整个应用程序中重复使用的组件。您将了解v-model
指令的工作原理,以及主应用程序和表单如何利用这些组件。
第四章,“使用 v-mask 进行输入掩码”,涉及使用v-mask
库来实现输入掩码以改善用户体验。您将学习如何实现第三方插件,以及如何将它们合并到自定义组件中。
第五章,使用 Vuelidate 进行输入验证,将带你了解如何向项目中添加 Vuelidate——一个强大的表单验证库,创建验证规则并将其应用到你的表单,以及如何将其整合到你的自定义组件中。
第六章,使用 Vuex 转移到全局状态,通过利用 Vuex 的强大功能,将当前应用程序的本地状态转移到全局状态。我们将把 Vuelidate 和我们的自定义组件整合在一起。
第七章,创建基于模式的表单,将所有先前的概念整合在一起,带你了解并创建一个渲染器组件,使你的应用程序完全基于模式驱动。它将对模拟 API 提供的 API 更改做出反应,并解释如何生成一个完全构建的表单,包括向模拟后端提交数据的方法。
为了充分利用这本书
为了让你更容易地跟随这本书,我必须对你已有的一些知识做一些假设。以下是你需要的基本要求清单,以便充分利用这本书:
-
你之前使用过 HTML、CSS 和 JavaScript,并且能够轻松创建基本的 Web 应用程序。
-
你熟悉
console.log
语句和在浏览器中调试 Web 应用程序的一般方法,比如 Chrome。 -
基本的终端命令知识。你至少应该知道如何使用
cd
命令导航文件夹。 -
你了解 Vue 的基本概念,比如状态、响应性、插值、计算属性和方法。确保查看官方指南的基本部分以供参考:
vuejs.org/v2/guide/
。 -
你有一台电脑和互联网连接,可以下载和安装所需的库和项目文件。
在本书的第一章中,我们将介绍如何按照简单的步骤列表设置你的项目。
下载示例代码文件
您可以从www.packt.com的帐户中下载本书的示例代码文件。如果您在其他地方购买了本书,可以访问www.packtpub.com/support注册,直接将文件发送到您的邮箱。
您可以按照以下步骤下载代码文件:
-
在www.packt.com上登录或注册。
-
选择“支持”标签页。
-
点击“代码下载”。
-
在搜索框中输入书名,并按照屏幕上的说明操作。
下载文件后,请确保使用最新版本的以下软件解压或提取文件夹:
-
WinRAR/7-Zip for Windows
-
Zipeg/iZip/UnRarX for Mac
-
7-Zip/PeaZip for Linux
本书的代码包也托管在 GitHub 上,网址为github.com/PacktPublishing/Building-Forms-with-Vue.js
。如果代码有更新,将在现有的 GitHub 存储库上进行更新。
我们还有来自丰富书籍和视频目录的其他代码包,可在github.com/PacktPublishing/
上找到。快去看看吧!
下载彩色图像
我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图像。您可以在这里下载:static.packt-cdn.com/downloads/9781839213335_ColorImages.pdf
。
代码演示
访问以下链接查看代码运行的视频:
使用的约定
本书中使用了许多文本约定。
CodeInText
:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。这是一个例子:“让我们开始安装v-mask
库。”
代码块设置如下:
<input
type="text"
v-model="form.telephone"
v-mask="'(###)###-####'"
>
任何命令行输入或输出都将按照以下方式书写:
> npm install v-mask
粗体:表示新术语、重要单词或屏幕上看到的单词。例如,菜单或对话框中的单词会以这种方式出现在文本中。这是一个例子:“返回到第一个标签页,响应和正文。”
警告或重要提示会以这种方式出现。提示和技巧会以这种方式出现。
第一章:设置演示项目
每一个伟大的应用程序部署都始于一行代码,而在我们面前还有很长的路要走,我们应该从一开始就开始。
在本书中,我们将使用 Vue CLI 3 来设置我们的项目结构。Vue CLI 是一个令人惊叹的工具,可以快速搭建 Vue 应用程序。Vue CLI 诞生于成为搭建应用程序的首选工具。尽管还有其他令人惊叹的解决方案,比如 Nuxt,但了解 Vue CLI 的基础知识将让您在大多数项目中上手。如果您以前没有使用过它,不用担心:我们将一起逐步深入设置。
在本章中,我们将涵盖以下主题:
-
将 Vue CLI 安装到我们的计算机上
-
创建我们的新项目
-
快速查看项目结构
技术要求
本章的要求如下:
-
您需要一台可以访问终端程序的计算机,例如苹果的终端或 Windows 的命令提示符。
-
Node 版本 8.9 或更高版本和Node 包管理器(npm):本章将提供安装说明。
-
您将需要一个您喜欢的集成开发环境(IDE)。一个很棒的免费 IDE 可以在
code.visualstudio.com/
找到
本章的代码文件可以在以下 GitHub 存储库中找到:
github.com/PacktPublishing/Building-Forms-with-Vue.js/tree/master/Chapter01
。
观看以下视频,查看代码运行情况:
将 Vue CLI 安装到我们的计算机上
在撰写本文时,Vue CLI 要求使用 Node 版本 8.9 或更高版本(建议使用 8.11.0+),因此我们需要确保您首先在开发计算机上设置了这个。
要检查是否已安装,请执行以下步骤:
-
打开一个终端(也称为命令行!)
-
执行
node -v
命令
如果您得到一个带有版本标签的输出,那么您已经安装了它,可以跳过。
如果您还没有安装 Node,请在浏览器中转到以下链接:nodejs.org。
您应该看到一个主屏幕和两个大绿色的下载按钮。我们将使用标有“Current”的按钮,如下截图所示:
因此,请继续点击按钮并按照您自己操作系统的安装说明进行安装。
安装完成后,请验证一切是否正常工作:
-
打开您的终端
-
执行
node -v
命令
您应该得到类似 v12.2.0 的输出,验证了 node 已经正确安装到您的系统中。
然而,要将 Vue CLI 实际安装到我们的系统中,我们仍然需要使用包管理器。
现在,当您安装 Node 时,实际上免费在系统上安装了npm
的副本。您可以通过在终端中输入npm -v
来验证这一点,和以前一样,您将得到一个版本号作为输出。
请注意,Vue CLI 要求 Node 版本在 8.9 或以上(推荐 8.11.0+),但请确保您在阅读本书时检查以下链接以获取确切的版本号:vuejs.org/guide/installation.html。
最后,现在是真正开始运行事情的时候了。再次打开您的终端,并运行以下命令:
> npm install --global @vue/cli
终端将继续下载所有所需的文件到您的计算机,并在全局可访问的路径中设置它们,以便您可以在计算机的任何地方使用此 CLI 工具。很棒,对吧?
请注意此命令上的--global
标志。这意味着您在计算机上全局安装此软件包。简而言之,这意味着您可以在文件系统的任何位置使用命令,而无需导航到特定文件夹。
供以后参考,您还可以使用--global
的简写,即简单的-g
。
再次,让我们通过在终端上运行vue --version
来检查一切是否安装正确。您应该会得到 Vue CLI 的版本号。
现在我们已经设置好了 CLI,我们可以开始创建我们的新项目。让我们在下一节深入了解如何做到这一点。
创建我们的新项目
进入您选择的一个文件夹,该文件夹将保存您的项目文件。不用担心,我们不需要设置服务器、虚拟主机或任何类似的东西。Vue CLI 实际上会在我们每次运行项目脚本时为我们设置一个开发服务器,因此您可以在任何您喜欢的地方创建它。
您现在要运行的命令是vue create <name>
,其中<name>
是您的项目名称,也是将要创建的文件夹。
我们将通过运行以下命令来创建我们的新项目:
> vue create vuetiful-forms
vuetiful-forms
部分的命令将命名项目文件夹。当然,你可以根据自己的需要自由命名。
运行此命令后,Vue CLI 将显示一个向导,让你配置项目的设置方式:
我们将选择手动选择功能,因为我们想要尝试并查看可以切换开关的选项。请注意,我们在这里做出的决定并不是最终的。任何东西都可以随后添加或移除,所以不用担心!
第一个屏幕向我们展示了可以选择的不同功能和包:
-
选择 Babel 和 Lint/Formatter,这是默认的两个选项。在本书的后面,我们将手动向项目添加 Vuex。
-
按下空格键选择任何选项,按下 Enter 键继续到下一个屏幕。
-
在 linter/formatter 配置屏幕上,使用仅包含错误预防的 ESLint 配置。
-
在下一个屏幕上,我们将选择在保存时进行代码检查。(如果你不喜欢自动代码检查,可以选择其他选项。)
-
对于我们的配置,选择将其存储在专用配置文件中,以尽可能保持我们的
package.json
文件整洁。 -
最后,如果你愿意,可以将此保存为未来项目的预设。
另外,请注意,根据你的选择,你可能会看到不同于我在这里解释的配置。
终端将再次开始工作,在幕后为你的新项目创建项目结构:
通过这个易于遵循的向导,你可以轻松地搭建所有项目,但是如果在此阶段没有选择特定选项,不用担心;Vue CLI 使得随后添加和移除插件变得非常容易!现在让我们快速看一下我们的项目。
项目结构的快速概览
打开你的新的 vuetiful-forms
文件夹在你喜欢的代码编辑器中。如果你还没有用于开发的集成开发环境,你可以从 code.visualstudio.com 免费获取一个非常好的。
你的项目结构将如下截图所示:
以下是你可以在结构中找到的快速概述:
-
node_modules: 这里保存着你的依赖项——你可以使用
npm
安装或移除的代码包。 -
public:这个文件夹将保存
index.html
,当您导航到应用程序的 URL 时,您的 Web 服务器将加载它。Vue 会自动注入它所需的所有文件,因此您不需要担心这里发生的事情。 -
src:这是您将放置所有代码、组件、资产等的地方。
在您的项目根目录中,您将看到一个名为.eslintrc.js
的配置文件,用于您的 ESLint 配置,.gitignore
用于 Git,package.json
和package-lock.json
或yarn.lock
文件用于包管理,以及根据您之前的选择而定的其他文件。
这些文件用于更改每个服务的偏好设置,如果您没有调整它们的经验,可以安全地忽略它们。
总结
到目前为止,您已经了解了使用 Vue CLI 构建应用程序的所有基础知识,并且已经初步了解了项目结构。
在下一章中,我们将启动并运行我们的项目,并开始处理实际的表单!
第二章:最简单的表单
好的!让我们毫不犹豫地开始(在美化之前稍作一些绕路)。我们将创建一个非常简单的带有表单的页面。这个表单将向用户询问一些基本的个人数据,表单的第二部分将用于更具体的问题。
在本章结束时,您将对如何在 Vue 中构建基本表单有扎实的理解,而且您还将快速复习基本的 Vue 概念,如v-model
、事件和属性。
在本章中,我们将涵盖以下主题:
-
使用 Bootstrap 入门
-
实际编写一些代码
-
将输入绑定到本地状态
-
提交表单数据
-
引入 Axios
技术要求
本章的代码可以在以下 GitHub 存储库中找到:
github.com/PacktPublishing/Building-Forms-with-Vue.js/tree/master/Chapter02
。
查看以下视频以查看代码的实际操作:
使用 Bootstrap 入门
让我们首先将 Bootstrap 4 作为项目的依赖项添加到我们的项目中,这样我们就不必考虑设计,可以专注于我们表单的功能。
Bootstrap 是一个流行的开源工具包,它为我们提供了一些预定义的类和样式,这样我们就可以让我们的应用程序看起来漂亮,而不必太担心样式。
要安装 Bootstrap 并为我们的项目设置,请按照以下步骤进行:
- 打开项目文件夹的终端,并使用以下命令安装依赖项:
> npm install bootstrap
- 太棒了!这将把包添加到我们的
node_modules
文件夹和package.json
中。现在,继续并将必要的样式导入到src/main.js
中。使用以下命令来执行:
import 'bootstrap/dist/css/bootstrap.min.css';
我们不会使用 Bootstrap 的脚本,所以我们只需要最小化的 CSS 就可以了。
让我们对我们的App.vue
文件进行一些清理,因为现在我们只有一些样板代码,但我们想要重新开始!所以,让我们开始清理:
- 用以下代码替换
App.vue
中的所有内容:
<template>
<div id="app">
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
- 通过在终端上运行以下命令来启动开发服务器:
> npm run serve
- 打开终端显示的链接(显示为本地)并在浏览器中应该看到一个空白屏幕。
瞧,这是伟大和重要的第一步的空白画布!耶!
让我们继续并开始着手实际的表单工作。现在是写一些代码的时候了。
实际编写一些代码
好了,够了设置——让我们写一些代码!我们将从一个非常简单的表单开始,这样我们的用户可以填写他们的个人信息。没什么疯狂的,只是小步走。
我们将向我们的表单添加三个字段。一个firstName
输入,一个lastName
输入和一个email
输入。最后,我们将添加一个Submit
按钮。
还记得我们安装 Bootstrap 吗?这就是它发挥作用的地方。我们要添加到标记中的所有类都将由 Bootstrap 自动样式化。
对您的App.vue
文件进行以下更改:
<template>
<div id="app" class="container py-4">
<div class="row">
<div class="col-12">
<form>
<div class="form-group">
<label>First Name:</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<label>Last Name:</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<label>Email:</label>
<input type="email" class="form-control">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
</template>
在上一个代码示例中,我们设置了一个带有row
的容器。在这个row
中,我们用三个不同的输入填充了它,两个text
类型(一个用于名字,一个用于姓氏),以及一个email
类型的输入。最后,我们添加了<button>
,它将作为提交表单的主要方式。
保存您的文件并检查您的浏览器。如果服务器仍在运行,您应该会自动看到更改。好吧,我同意这有点令人失望,但我确实说过我们从一个简单的例子开始,这就是最简单的例子!
表单是完全功能的,甚至可以单击提交按钮使其提交给自身并实现绝对没有任何作用。很棒!但让我们用一些 Vue 来调味一下。
将输入绑定到本地状态
Web 应用程序中表单的目的是捕获一些用户输入并能够对其进行操作。在我们的示例中,我们仍然没有任何方法使用 JavaScript 访问用户的输入以进行我们美好的 Vuetiful 计划,所以让我们从那里开始。
请注意,您不一定要将表单数据包装在次要对象中,但我发现这样更清晰——特别是当您开始向组件添加其他数据属性时,这些属性可能与您的表单无关。
在您的App.vue
文件的实例上创建一个新的data
属性。在其中,我们将声明一个form
对象,它将依次包含每个输入的属性:
<script>
export default {
name: 'app',
data() {
return {
form: {
firstName: '',
lastName: '',
email: ''
}
}
}
}
</script>
为了将我们的输入值绑定到内部状态,我们需要使用 Vue 的v-model
属性。因此,让我们为每个输入添加v-model
。这样,每当用户输入或删除信息时,输入元素的值将绑定到我们的data
属性。
请记住,v-model
不是一个神奇的属性。它是两件事的简写:
- 它绑定了我们输入框的
input
事件:
v-on:input="form.name = $event.target.value"
- 它将
value
属性绑定到我们的data
属性:
v-bind:value="form.firstName"
继续在所有输入中添加v-model
:
...
<div class="form-group">
<label>First Name:</label>
<input
v-model="form.firstName"
type="text"
class="form-control"
>
</div>
<div class="form-group">
<label>Last Name:</label>
<input
v-model="form.lastName"
type="text"
class="form-control"
>
</div>
<div class="form-group">
<label>Email:</label>
<input
v-model="form.email"
type="email"
class="form-control"
>
</div>
下面的屏幕截图显示了 Vue 开发者工具显示我们的表单与数据内部状态之间的双向数据绑定:
干得好!现在,这并不是非常令人印象深刻,但我们正在为未来打下基础。
在接下来的部分中,我们将看看如何处理表单提交并发送到 API 端点。
提交表单数据
目前,当单击提交按钮时,表单将提交到相同的 URL。这不是 Vue 的魔法 - 这只是默认的<form>
行为,特别是因为我们没有在标签上指定action
属性。
在大多数实际场景中,您希望在提交表单之前执行一些操作。最常见的操作可能是验证一些输入,或者甚至使用诸如 Axios 之类的库进行异步调用来覆盖默认的提交行为。
首先,我们需要确保当用户单击提交按钮时,我们阻止表单自行提交。我们还希望绑定一个新的方法来处理点击。
让我们首先绑定表单的submit
事件。请记住,我们希望为事件添加.prevent
修饰符,以便在提交表单时,不会触发默认行为,而我们的函数将按预期运行:
<form @submit.prevent="onSubmit">
...
</form>
太棒了!现在我们需要在App.vue
文件的配置中创建这个新的onSubmit
方法。在进一步详细说明之前,让我们在click
方法处理程序内使用console.log
来验证它是否有效。
将此代码作为export default
声明内的属性添加:
methods: {
onSubmit() {
console.log('click');
}
}
只是为了验证一切是否正常工作,继续打开浏览器,点击几次提交按钮。检查控制台;日志应该显示点击。到目前为止,一切都很好 - 我们已经成功控制了表单的行为。
让我们创建一个非常基本的验证方法作为示例。我们将验证三个字段的输入长度是否> 0
(不为空)。在后面的章节中,我们将介绍 Vuelidate,它将为我们的表单提供更深入和强大的验证。
让我们创建一个名为formIsValid
的新计算属性,它将检查我们刚刚讨论的条件。将以下内容添加到App.vue
中:
computed: {
formIsValid() {
return (
this.form.firstName.length > 0 &&
this.form.lastName.length > 0 &&
this.form.email.length > 0
);
}
}
现在我们有一个计算属性来检查我们表单的状态,让我们在onSubmit
方法中实际使用它。我们将验证this.formIsValid
是否为true
,如果不是,我们将简单地返回并阻止表单提交。现在,我们将仅使用console.log
进行确认。
将onSubmit
方法调整为以下内容:
onSubmit() {
if (!this.formIsValid) return;
console.log('Send my form!');
}
在浏览器上进行测试。如果您缺少任何字段,您将无法得到console.log
,因为验证将失败。如果您填写它们并点击提交按钮,您将在控制台中收到消息。
在下一个块中,我们将引入第三方库 Axios,以帮助我们发送数据。
引入 Axios
我们表单的下一步是实际上让表单将用户的数据发送到我们的服务器。举例来说,数据实际上不会被存储在任何地方,但我们将看一下创建 POST 调用的步骤,大多数表单将用于将数据传输到 API 或服务器端点。
Axios 是一个非常棒和流行的库,用于向服务器发送和接收数据。我个人推荐它作为您的 Vue 应用程序中进行任何 HTTP 调用时的首选。您可以在这里找到官方的 GitHub 页面:github.com/axios/axios。
按照以下步骤准备好您的项目中的 Axios:
- 打开您的终端并运行以下命令:
> npm install axios
-
我们需要一个 API 端点来进行调用。由于我们手头没有任何服务器,为了保持简单,我们将使用一个名为 Mockoon 的应用程序。前往mockoon.com/#download下载适用于您操作系统的应用程序。安装完成后,启动它。
-
在第二列中,您将看到两个示例路由;我们感兴趣的是 POST 路由到/dolphins(坦白说,我更喜欢海獭,但我会接受这个)。继续点击顶部的绿色播放三角形;这将在
localhost:3000
上启动一个服务器,默认情况下,但如果默认设置不适用于您,您可以更改端口。 -
现在,Axios 已经作为项目的依赖项添加,我们可以将其导入到
App.vue
中,以利用其不同的方法。 -
在
App.vue
文件的顶部添加导入语句,就在开头的<script>
标签之后,在export default {
行之前:
import axios from 'axios';
通过这个导入,我们现在可以在这个组件的任何地方使用 Axios。请记住,如果以后我们想在另一个组件或文件中使用它,我们将不得不再次导入它。
- 让我们再次更新
onSubmit
按钮。这一次,我们将摆脱console.log
,然后用 Axios 进行async
调用:
onSubmit() {
if (!this.formIsValid) return;
axios
.post('http://localhost:3000/dolphins', { params: this.form })
.then(response => {
console.log('Form has been posted', response);
}).catch(err => {
console.log('An error occurred', err);
});
}
每个 Axios 方法都返回一个 promise,这是一个原始的 JavaScript 对象。当这个 promise 解析时,也就是说,当实际的 HTTP 请求完成时,then
块就会被调用!关于 promises 的更多信息,MDN 在developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise上有一个很好的资源。
如果你现在去浏览器尝试一下,你会发现,当点击提交按钮时,我们的onSubmit
方法被触发,console.log
成功执行。在这一点上,我们可以说我们有一个非常基本的(但可悲的无用)表单!
让我们再走一步,实际上在表单有效之前禁用输入按钮。(请记住,我们的验证现在非常薄弱,但我们以后会加强它。)
回到你的模板,让我们将按钮的:disabled
属性与我们的计算属性formIsValid
关联起来:
<button
:disabled="!formIsValid"
@click.prevent="onSubmit"
type="submit"
class="btn btn-primary"
>
Submit
</button>
再次在浏览器中测试一下,你会发现在表单实际填写之前,输入按钮是灰色的。很整洁!
总结
在本章中,我们已经迈出了创建一个简单数据收集表单的第一步。我们使用 Bootstrap 对其进行了样式化,并钩入了<form>
事件。最后,我们使用 Axios 和 Mockoon 将数据发送到一个虚拟后端进行测试。
在下一章中,我们将探讨利用 Vue 的强大功能来构建可重用的表单组件。
第三章:创建可重用的表单组件
Vue 最强大的部分之一是它能够创建组件。
组件是可重用的代码片段,通常包括模板、脚本和样式。组件的惊人之处在于,你可以将特定元素或一组元素的所有逻辑封装到一个单元中。
开始以组件的方式思考的一个好方法是将日常物品分解为简单的、更小的部分。(请在你的脑海中!)
举个例子,你正在使用的计算机。作为一个整体,整个系统可以称为计算机。现在再进一步分解——它有一个显示器、一个键盘和一些电缆。现在拿键盘来分解。现在你有一个容器,这个容器有键。每个键都是一个单一的组件,它重复出现,具有一些在它们之间变化的属性。键上的标签会改变,有时也会改变大小。
那么这个关键组件呢?你能进一步分解吗?也许可以!但是值得吗?键盘键是一个很好的单一组件。它有清晰的属性来定义它,我们可以清晰地定义它的内部功能。当它被按下时,我们需要告诉包含它的人,一个键被按下,以及该键的值。
这种将某物进行分解的过程也可以应用到任何 Vue 应用程序中。从整个应用程序作为一个整体单元开始,然后将其分解。
现在,我们当前的表单是一个大块在App.vue
中,这不是理想的。让我们创建一些组件!
在本章中,我们将涵盖以下主题:
-
将应用程序分解为可重用组件
-
理解自定义组件中的
v-model
-
实现自定义输入和选择组件
技术要求
本章的代码可以在以下 GitHub 存储库中找到:
github.com/PacktPublishing/Building-Forms-with-Vue.js/tree/master/Chapter03
。
查看以下视频以查看代码的实际操作:
将表单分解为组件
看看App.vue
,让我们从我们可以创建的最小可能组件开始。如果你仔细看,你会发现代码中有一个重复的模式——这通常是一个好迹象,表明某些东西可能成为一个很好的组件!
在我们的<form>
元素中,我们有三个不同的文本输入。其中两个是text
类型,一个是email
类型。看起来我们需要一种方法将这些值分配给type
属性。属性对象可能是一个简单的解决方案!
作为一个快速提醒,这是表单的当前代码:
<div class="form-group">
<label>First Name:</label>
<input v-model="form.firstName" type="text" class="form-control">
</div>
<div class="form-group">
<label>Last Name:</label>
<input v-model="form.lastName" type="text" class="form-control">
</div>
<div class="form-group">
<label>Email:</label>
<input v-model="form.email" type="email" class="form-control">
</div>
继续在src/components
文件夹中创建一个新文件,命名为BaseInput.vue
。就我个人而言,我喜欢以Base
开头命名我的基本输入组件;这样,我就知道它是我在应用程序中能找到的最简单的输入形式。
如果我需要制作一个扩展或以某种方式使用Base
的组件,那么我只需导入BaseInput
组件,并进行一些调整!但是,您可以随意使用任何您喜欢的命名约定。如果您想要一些关于命名组件的实际样式指南和最佳实践,请参考官方指南:vuejs.org/v2/style-guide/
。
让我们将App.vue
中的第一个输入复制到我们的新组件中的<template>
标签中,这样我们就有了一个基础来工作:
<template>
<div class="form-group">
<label>Name:</label>
<input v-model="form.firstName" type="text" class="form-control">
</div>
</template>
<script>
export default {
}
</script>
我们需要做的第一件事是弄清楚如何摆脱硬编码的值;毕竟,将代码提取到组件中的目的是使其具有动态性和可重用性。
让我们创建一个属性对象来保存label
的值(名称为string
):
<script>
export default {
props: {
label: {
type: String,
required: true
}
}
}
</script>
我们将使用对象表示法来声明属性,这样我们可以确保任何使用我们组件的人至少会在浏览器控制台中被警告,如果他们忘记定义标签。
现在,让我们回到模板,实际上用新创建的属性对象替换这个值:
<template>
<div class="form-group">
<label>{{ label }}</label>
<input v-model="form.firstName" type="text" class="form-control">
</div>
</template>
还有一个,类型呢?我们可能会想要在电子邮件和最终密码字段中使用这个(我们会的)。
让我们为此创建一个新的属性对象,并像以前一样绑定它:
props: {
label: {
type: String,
required: true
},
type: {
type: String,
default: 'text',
validator(value) {
return ['text', 'email', 'password'].includes(value);
}
}
}
我们的新属性类型有一个默认值,在组件实现时,如果该属性缺失,将使用默认值。
validator
是一个函数,它验证!它接受一个参数,即传递到属性的值,并且必须返回一个布尔值来验证该值是否可接受用于属性(validator
验证!)。
在这种特殊情况下,我们只是检查它是否是我们允许的三个选择之一:text
,email
或password
。
既然我们已经准备好了,让我们更新<input>
:
<input v-model="form.firstName" :type="type" class="form-control">
到目前为止,一切都很好!除了还有一件事情还缺少,我们需要重构。你能发现吗?
到目前为止,我们已经看到了如何将表单分解为组件。现在让我们更深入地了解v-model
,以及在创建动态组件时的重要性。
在自定义组件中理解 v-model
正如你所知,v-model
是v-on:input
和v-bind:value="value"
的简写形式。它允许我们双向绑定特定元素的值,以及它发出的事件到我们内部状态属性之一。
然而,在谈论组件组合时,我们需要考虑额外的事情。
为了让自定义组件能够实现v-model
协议,我们必须确保发生两件事。没错!我们需要确保组件有一个value
属性,并且它$emits
一个输入事件。
有一种方法可以通过使用model
属性来更改这种默认行为,但这超出了本书的范围。如果你想告诉你的组件使用不同的属性或不同的事件来使用v-model
,请查看vuejs.org/v2/api/#model
。
让我们将这个理论付诸实践。我们将修改我们的BaseInput
组件,以便能够使用v-model
绑定。首先,让我们添加一个value
属性,并将其挂钩到<input>
上:
props: {
label: {
type: String,
required: true
},
type: {
type: String,
default: 'text',
validator(value) {
return ['text', 'email', 'password'].includes(value);
}
},
// Add this new prop
value: {
type: String,
required: true
}
}
现在我们有了新的value
属性,我们需要将其绑定到<input>
的值上。不过,一定要将旧的v-model
从中移除!看一下下面的例子:
<input :value="value" type="text" class="form-control">
差不多了;现在我们需要确保<input>
在更新时触发输入事件。因此,我们需要添加一个事件处理程序来$emit
这个信息。
重要!在我们继续之前,让我告诉你一个非常常见的陷阱,当使用v-model
和表单时。并非所有的输入都是一样的!<input>
文本元素(text
,email
和password
)和<textarea>
很容易。它们触发我们可以监听到用于v-model
绑定的输入事件。但是,select
,checkboxes
和radio
呢?
Vue 文档非常清晰,所以我要引用一下:
“v-model
在内部使用不同的属性并为不同的输入元素发出不同的事件:
-
text
和textarea
元素使用value
属性和input
事件; -
checkboxes
和radiobuttons
使用checked
属性和change
事件; -
select
字段使用value
作为属性和change
作为事件。
现在我们已经搞清楚了这个理论,让我们实际监听我们的事件:
<input
:value="value"
:type="type"
class="form-control"
@input="$emit('input', $event.target.value)"
>
恭喜!我们的BaseInput
组件已经准备好使用了。
现在我们对v-model
和自定义组件有了清晰的理解,我们将在表单中使用我们的组件。这将使它更易读、动态和易于维护。
实现自定义输入组件
创建可重用的自定义组件是 Vue 的核心部分,但是为了使组件真正有用,我们必须实际上使用它们!
打开您的App.vue
文件,让我们用我们的自定义组件替换三个<div class="form-group">
元素。
首先要做的是将组件导入到我们的文件中。让我们先搞定这个。在<script>
元素的顶部添加以下导入,如下所示:
import BaseInput from '@/components/BaseInput';
仅仅导入文件是不够的;我们实际上必须将组件添加到文件的组件属性中,这样我们才能在模板中使用它。我们目前在 Vue 实例中没有这样的属性,所以让我们在name
和data()
之间创建一个:
...
components: { BaseInput },
...
现在我们已经注册了我们的组件,并在App.vue
文件中导入了它,我们可以进入模板,用我们的新组件替换旧的输入:
<BaseInput
label="First Name:"
v-model="form.firstName"
/>
<BaseInput
label="Last Name:"
v-model="form.lastName"
/>
<BaseInput
label="Email:"
v-model="form.email"
type="email"
/>
回到您的浏览器,玩一下这个应用程序。您会发现,即使实际上没有发生任何变化,表单现在是由可重用的输入组件驱动的——例如,如果我们需要更新输入的 CSS,我们只需在那个文件中更改一次,整个应用程序就会更新以反映这些变化。
再次打开 Vue DevTools,并确保选择了第一个图标(组件结构的图标)。深入结构,您将看到三个BaseInput
组件在那里表示。
您甚至可以点击每一个,属性面板将清楚地显示每一个的独特之处——属性!
在下面的截图中,您可以看到,当我在“名称:”字段中输入我的名字时,组件会在其值属性中反映出来:
还有一件事!在表单中输入一些值,然后查看 props 框,它将实时更新您的值属性中的双向绑定。现在,点击 DevTools 中的第三个图标,看起来像一堆点——这是事件视图。
再次在其中一个输入框中输入一些值,您会看到事件框将填满条目。点击其中一个,您会注意到我们的输入事件在每次按键时都被触发。
这是两种不同的操作——值得到更新和输入事件被触发构成了v-model
在工作中所做的工作,正如我们之前讨论的那样!
让我们看一下以下的屏幕截图:
在前面的屏幕截图中,您可以看到<BaseInput>
组件是如何发出输入事件的——payload
是用户在表单中输入的内容。
再来一次——带有下拉选项!
在我们结束本章之前,让我们构建一个自定义组件,它包装了一个下拉输入,以便回顾我们迄今为止学到的知识。
首先创建组件文件——我们将其命名为BaseSelect.vue
,并将其放在components
文件夹中。
就像我们对BaseInput
所做的那样,首先我们将定义我们的 HTML 模板。我们现在会留一些属性为空,因为我们稍后会绑定它们。我们还将设置一些虚拟数据以便轻松测试。在组件创建中,您会发现小步骤是前进的方式!
将以下代码添加为BaseSelect
的模板:
<template>
<div class="form-group">
<label>Label here</label>
<select class="form-control">
<option value="">Test!</option>
<option value="">Me!</option>
<option value="">:D</option>
</select>
</div>
</template>
看起来不错!让我们将这个新组件导入到App.vue
中,并在我们的模板中,以便我们可以在浏览器中测试它的功能。按照给定的步骤来做:
- 在
script
元素的顶部导入组件,紧挨着BaseInput
导入语句:
import BaseSelect from '@/components/BaseSelect';
- 将
BaseSelect
添加到您的components
声明中:
components: { BaseInput, BaseSelect },
- 在
<template>
元素内创建BaseSelect
的实例,就在最后一个BaseInput
组件下面,也在包含输入按钮的div
之前:
...
<BaseSelect />
...
检查您的浏览器,您会看到我们新选择的组件正在发挥作用。她不是很漂亮吗?
让我们再进一步,我们迫切需要一些props
。让我们从添加label
开始;我们可以从模板中看到它需要被动态化。
在新的script
元素内创建您的props
对象,并将其添加到列表中:
<script>
export default {
props: {
label: {
type: String,
required: true
}
}
}
</script>
现在,前往模板并动态绑定它们。我们需要使用一些插值使<label>
的内容动态化:
<template>
<div class="form-group">
<label>{{ label }}</label>
<select class="form-control">
<option value="">Test!</option>
<option value="">Me!</option>
<option value="">:D</option>
</select>
</div>
</template>
到目前为止,一切都很好!回到App.vue
,并将这些新的props
添加到我们的示例组件中:
<BaseSelect
label="What do you love most about Vue?"
/>
在浏览器中测试一下,确保没有出现问题。到目前为止,组件运行得相当顺利,但它显示的选项仍然是硬编码的。让我们实现一个options
属性,这次它将是一个对象数组,我们将用它来填充select
选项。
回到BaseSelect.vue
,并创建新的属性:
options: {
type: Array,
required: true,
validator(opts) {
return !opts.find(opt => typeof opt !== 'object');
}
}
对于validator
对象,我们将使用 JavaScript 数组,以找到一种方法来查看数组中是否存在一个不是对象的元素。如果找到了某些东西,find
方法将返回它,!
将对其进行评估为false
,这将引发控制台错误。如果找不到任何东西(并且所有元素都是对象),那么find
将返回undefined
,!
将转换为true
,并且验证将通过。
有关find
方法的更多信息,请查看以下链接:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
。
让我们在<select>
元素内部实现一个v-for
循环:
<select class="form-control">
<option
v-for="opt in options"
:key="opt.value"
:value="opt.value"
>
{{ opt.label || 'No label' }}
</option>
</select>
v-for
循环将抓取 options 中的每个元素,并在<select>
内创建一个新的<option>
元素;不要忘记设置:key
属性!
如果您想了解更多关于:key
的信息,即何时使用它以及原因,请查看我在以下链接中的文章:www.telerik.com/blogs/in-vue-when-do-i-actually-need-the-key-attribute-and-why
。
我们需要确保 options 中的每个对象都有label
和value
属性,但如果label
缺失,我们将提供一个默认值。
回到App.vue
,我们将在data()
内部创建一个名为loveOptions
的新内部state
属性,它将保存特定<Select>
的选项:
return {
form: ...,
loveOptions: [
{ label: 'Fun to use', value: 'fun' },
{ label: 'Friendly learning curve', value: 'curve' },
{ label: 'Amazing documentation', value: 'docs' },
{ label: 'Fantastic community', value: 'community' }
]
}
现在我们已经设置好了,去模板并将其绑定到我们的BaseSelect
组件的options
prop 上:
<BaseSelect
label="What do you love most about Vue?"
:options="loveOptions"
/>
保存后返回浏览器并检查选项。它活了!
还有一件事情缺失,我们需要将其添加到这个组件中,即v-model
功能。我们需要创建一个value
prop,使所选的option
属性使用它,并确保我们从组件内部触发输入事件。
“记住,记住,v-model
的规则,属性绑定和发射。我不知道任何理由,v-model
系统,应该被遗忘。” - Vue Fawkes
在这种情况下,由于我们将使用 v-model
与 select
,请记住我们需要监听变化,甚至是内部的变化!另一个需要注意的是,您可能会想要在 select
标签上放置一个 :value
绑定,这不是与选择一起工作的正确方式!
HTML 中的 <select>
元素没有 value
属性;它所做的是将 selected
属性应用到其中的 option
元素,该元素保存当前值。
- 添加
value
属性:
value: {
type: String,
required: true
}
- 您将使用
value
属性来检查此选项的值是否等于它。确保在select
元素触发change
事件时发出input
:
<select
class="form-control"
@change="$emit('input', $event.target.value)"
>
<option
v-for="opt in options"
:key="opt.value"
:value="opt.value"
:selected="value === opt.value"
>
{{ opt.label || 'No label' }}
</option>
</select>
- 返回到
App.vue
并将v-model
绑定到这个新元素。您需要在data()
中的form
属性中创建一个名为love
的新属性,并将v-model
属性添加到BaseSelect
元素中:
form: {
firstName: '',
lastName: '',
email: '',
love: 'fun'
},
BaseSelect
元素现在将具有 v-model
绑定:
<BaseSelect
label="What do you love most about Vue?"
:options="loveOptions"
v-model="form.love"
/>
最后,检查您的浏览器,看看一切是否正常。进入 DevTools 并检查您的 App 组件 - 当您切换选择的值时,它也会更新!
总结
在本章中,我们已经通过将单例应用程序或表单解构为可重用的动态组件的过程。我们已经涵盖了一些重要的核心 Vue 功能,比如 v-model
,属性和事件。
在下一章中,我们将加快速度,实现一个与用户体验(UX)相关的功能,即输入掩码!
第四章:使用 v-mask 进行输入掩码
任何成功表单的关键方面之一是清晰度。如果用户发现表单易于使用和理解,他们更有可能填写并提交表单。在本章中,我们将研究输入掩码。您将学习如何快速轻松地将掩码应用于表单输入,并使用真实示例(如电话号码)根据您的需求进行配置。
究竟什么是输入掩码?它们是预定义的结构,用于显示输入的数据。例如,如果您要对电话输入进行掩码处理,您可能希望它显示为(123) 234-5555,而不仅仅是1232345555。您可以清楚地看到,第一个示例不仅更容易阅读,而且还传达了字段试图实现的含义。
输入掩码是一个很好的功能,可以将您的 UX 提升到另一个水平,而且非常容易实现,这要归功于开源库,如v-mask
。GitHub 存储库页面可以在以下链接找到:github.com/probil/v-mask
。
在本章中,我们将快速了解如何在现有项目的基础上实现此库。
在本章中,我们将涵盖以下主题:
-
安装
v-mask
库 -
探索
v-mask
指令 -
增强我们的自定义输入
技术要求
本章的代码可以在以下 GitHub 存储库中找到:
github.com/PacktPublishing/Building-Forms-with-Vue.js/tree/master/Chapter04
。
查看以下视频以查看代码的实际操作:
安装 v-mask 库
让我们开始安装v-mask
库。为了让我们的项目使用它所提供的功能,我们首先需要将其添加到我们的项目依赖项中。按照以下步骤执行此操作:
- 打开您的终端并输入以下命令将库添加到我们的依赖项中:
> npm install v-mask
- 我们需要将其添加到 Vue 作为插件,因此转到
main.js
,让我们导入它并让 Vue 知道我们要将其注册为所有应用程序的插件。在import App
行之后添加以下代码:
import VueMask from 'v-mask'
Vue.use(VueMask);
现在我们已经注册了我们的插件,我们可以访问一个新的指令:v-mask
。我们可以直接将这个新指令添加到我们的<input>
元素上,该库将通过读取用户的输入并调整字段的显示来处理幕后的掩码。
首先让我们在常规输入上尝试一下,然后我们将向我们项目的组件添加一些属性:
- 转到
App.vue
,在电子邮件输入后创建一个新的<input>
元素:
<input type="text" />
如果我们在此字段中输入电话号码,我们将获得默认的输入行为。什么都可以。因此,让我们对其应用telephone
号码掩码。我们的新v-mask
库要求我们将其应用到的每个字段都需要进行 v 模型化,因此让我们首先完成这项工作。
- 在
form
对象的data()
中添加一个新的telephone
属性:
form: {
...
telephone: ''
},
- 现在,返回到我们的新
<input>
元素并应用v-model
。我们现在还将添加v-mask
指令,如下所示:
<input
type="text"
v-model="form.telephone"
v-mask="'(###)###-####'"
>
返回浏览器,再次尝试输入。当您输入时,您将看到它被很好地格式化为我们期望的电话号码。
在五个简单的步骤中,我们已经为我们的一个表单字段添加了输入掩码。在下一节中,我们将更深入地了解v-mask
指令为我们做了什么。
探索 v-mask 指令
当我们将v-mask
库添加到我们的项目中,并在main.js
中添加了插件时,该库为我们创建了一个新的指令v-mask
。但是,指令到底是什么?我们知道它看起来像 HTML 属性,但还有什么?
指令可以定义如下:
“指令是带有v-
前缀的特殊属性。指令属性值预期是单个 JavaScript 表达式(除了v-for […]
之外)。指令的作用是在其表达式的值发生变化时,对 DOM 应用响应式的副作用。”- 官方 Vue 文档。
好的,看起来我们有一个特殊的属性可以修改元素。这听起来就像我们在应用到输入元素时看到的情况。但是,我们放入此指令的实际表达式或值是如何工作的呢?
我们从示例中知道我们正在传递一个字符串,并且您可以看到在组成v-mask=""
属性的双引号内,我们设置了一对新的单引号('
)。这意味着此属性内的表达式是 JavaScript,并且我们正在传递给它一个字符串值。
从查看v-mask
库文档,我们知道我们有一些特殊的占位符字符,可以在我们的掩码中使用。这些特殊字符如下表所示:
# |
数字(0-9) |
---|---|
A |
任何大小写字母(a-z,A-Z) |
N |
数字或字母 |
X |
任何符号 |
? |
可选的(下一个字符) |
以显示一天中的时间为例;您可以将其定义如下:
v-mask="'##:##'"
这意味着此输入将接受两个数字,从 0 到 9(##
),后跟一个:
字符,然后是另外两个数字(##
)。
任何不符合此模式的内容都将被输入忽略。
v-mask
是一个非常强大的库,它允许我们通过组合这些简单的规则来自定义我们希望输入如何显示。在下一节中,我们将修改我们的自定义输入,以便能够利用输入掩码的功能。
增强我们的自定义输入
我们已经付出了很多工作来创建我们的令人敬畏的自定义BaseInput
,所以我们肯定希望继续使用它!
按照以下步骤修改BaseInput
并允许输入掩码:
- 回到
App.vue
并将<input>
元素切换为<BaseInput>
组件:
<BaseInput
label="Telephone"
type="text"
v-model="form.telephone"
/>
现在让我们进入BaseInput.vue
并创建一个新的 prop;我们将称其为mask
,并将其默认为一个空字符串。重要的是将其默认为一个空字符串,否则指令将尝试匹配它,如果没有声明掩码,我们将无法在字段中输入!
- 将其添加到您的
props
对象中:
...,
mask: {
type: String,
required: false
}
- 现在,回到
App.vue
并更新我们的电话BaseInput
以使用mask
属性:
<BaseInput
label="Telephone"
type="text"
v-model="form.telephone"
:mask="'(###)###-####'"
/>
全部完成!返回到您的浏览器,并在字段中添加一些数字,您应该可以看到一个漂亮的电话掩码与您的自定义组件一起工作!
总结
在本章中,我们已经学会了如何利用v-mask
库的强大功能来对我们的表单应用输入掩码。输入掩码是一种强大而简单的方式,可以为用户提供更好的体验,在构建甚至是最简单的表单时,不应忽视它!
在下一章中,我们将进一步学习并查看如何使用强大的库Vuelidate
进行表单验证!
第五章:使用 Vuelidate 进行输入验证
在生产就绪的表单中,验证用户输入是必须的。即使在服务器端,应用程序也应该对传递给它们的所有数据进行双重检查,同时在前端对数据进行预验证应该是任何有经验的开发人员的强制性实践。
在这一章中,我们将看一下一个非常著名和强大的表单验证库 Vuelidate。您将学习如何在项目中使用这个库,并且能够成功地用它来验证用户输入。
值得庆幸的是,在 Vue 中,我们有一些不同的选项可以选择第三方库,比如 Vuelidate、VeeValidate,甚至 Vuetify 都有自己的验证方法。
在这一章中,我们将涵盖 Vuelidate。从安装到创建规则并将其应用于我们的表单输入,以及使用错误状态来通知用户存在问题。
本章将涵盖以下主题:
-
安装依赖项
-
创建验证规则
-
将验证移入我们的自定义输入
-
添加最后的修饰
技术要求
本章的代码可以在以下 GitHub 存储库中找到:
github.com/PacktPublishing/Building-Forms-with-Vue.js/tree/master/Chapter05
。
查看以下视频,看看代码是如何运行的:
安装依赖项
让我们首先将 Vuelidate 作为一个依赖项安装到我们的项目中,然后我们将用它进行验证。按照以下步骤进行:
- 打开终端并执行以下命令:
> npm install vuelidate
一旦库被安装,我们必须将其导入到main.js
中并将其用作插件,以便它在全局范围内对所有组件都可用。
- 在
main.js
中添加以下代码,放在导入Vue
和App
的代码之后:
import Vuelidate from 'vuelidate';
Vue.use(Vuelidate);
现在 Vuelidate 已经安装并成为我们项目依赖的一部分,我们准备让它承担一些繁重的工作。在下一节中,我们将创建我们的验证规则。
创建验证规则
当我们通过Vue.use
将 Vuelidate 添加到我们的项目中时,该库会在我们的组件上添加一个新的保留属性:validations
。
这个属性被添加到组件的配置对象上,与data()
、computed
等一起。它也将是一个对象,为我们想要验证的每个输入保留一个属性。
让我们创建这个属性并设置一个新的输入,没有自定义组件包装器进行测试。一旦我们理解了基础知识,我们就可以开始将所有这些内容翻译成我们的BaseInput
和BaseSelect
组件。
按照以下步骤创建验证规则:
- 在
App.vue
中的BaseInput
的telephone
对象下面创建一个新的<input>
表单:
<input type="text" v-model="form.website" />
- 记得将这个新属性
website
添加到data()
的form
对象中:
form: {
firstName: '',
lastName: '',
email: '',
love: 'fun',
telephone: '',
website: ''
},
现在,让我们实际创建一个validations
属性;现在,我们只会添加form.website
的验证。
- 将其放置在
component
对象的顶层,与您的data()
和计算属性处于同一级别:
validations: {
form: {
website: {
// our validations will go here
}
}
}
对于这个特定的字段,我们希望确保验证用户提供的输入是一个有效的 URL。在 Vuelidate 中,我们有几个内置的验证器可以直接使用。完整列表可以在vuelidate.netlify.com/#sub-builtin-validators
找到。
为了验证输入是否为有效的 URL,我们有 URL 验证器。但是,为了将其添加到我们网站的validators
对象中,我们必须首先导入它。Vuelidate 允许我们只导入我们实际要使用的验证器;这样,我们可以确保我们部署的代码保持较小。
- 在
App.vue
中的其他导入附近添加以下导入语句:
import { url } from 'vuelidate/lib/validators';
- 现在我们已经导入了语句,我们最终可以将其添加到
validations.website
对象中:
validations: {
form: {
website: {
url // Validate that the "website" input is a valid URL
}
}
},
设置好规则就够了。记得我们之前创建的新的<input>
表单来保存v-model="form.website"
吗?我们需要对v-model
的设置进行一些调整,以便 Vuelidate 负责验证。
除了我们之前用来设置规则的validations
属性之外,Vuelidate 还为我们在组件实例内部提供了一个新属性:$v
。
$v
是一个特殊的对象,它保存了我们验证结构的副本。除其他事项外,一个显著的特点是,它为我们添加到validations
中的每个元素都有一个$model
属性。Vuelidate 将成为我们的中介模型,并且反过来,它将自动绑定到我们data()
中的form.website
属性。
让我们来看看实际操作中是怎样的:
- 更新
<input>
网站元素,使用 Vuelidate 期望的新的v-model
格式。此外,我们将在其下插入$v
对象,以便您可以更清楚地看到幕后发生了什么,如下所示:
<input type="text" v-model="$v.form.website.$model" />
<pre>{{ $v }}</pre>
- 回到你的浏览器,看看
$v
对象的结构,在你在新的表单字段中输入任何内容之前。
要特别注意的第一件事是form.website
对象。在此对象内部,Vuelidate 将保持此输入的验证状态。$model
属性将保存用户的输入,就像我们告诉v-model
要做的那样。$error
属性实际上将切换布尔值,并且会告诉我们输入是否有错误。
尝试在字段中输入一些随机的胡言乱语,并观察更新的属性。$error
属性将更新为true
,表示存在错误。与 URL 规则直接关联的url
属性将切换为false
,表示未满足 URL 验证条件。
- 让我们在
<input>
上添加一些 CSS 绑定,以便在我们的输入上直观显示出未通过验证的情况:
<input
type="text"
v-model="$v.form.website.$model"
class="form-control"
:class="{
'is-valid': !$v.form.website.$error && $v.form.website.$dirty,
'is-invalid': $v.form.website.$error
}"
/>
在我们进一步解释之前,请在浏览器中尝试一下。尝试输入一个有效的 URL,例如google.com
,并注意输入如何反映您的更改。
:class
绑定是一种在 Vue 中有条件地向任何 HTML 元素添加类的方法。在我们这里使用的语法类型中,它允许我们设置一个键值对,其中键定义了我们要切换的类,例如is-valid
。
该值是一个将被评估的 JavaScript 条件,以确定是否应该应用该类。这些条件是响应式的,并且每当条件的依赖项发生变化时,将被重新执行。
在我们的示例中,只要没有$error
并且输入是$dirty
,is-valid
就会被切换为on。如果你想知道为什么我们还要检查$dirty
,请尝试删除条件的这一部分,然后重新加载浏览器。您会立即注意到,即使元素中没有任何值,输入上也会出现绿色边框和复选标记。我们确定<input>
是否在任何时候被用户修改的方式是通过$dirty
属性;在这种情况下,从用户体验的角度来看,直到实际有一些输入时才显示有效的视觉提示是有意义的。
在is-invalid
的情况下,我们正在检查字段中是否存在任何$errors
,并使用漂亮的红色边框和 x 图标设置字段。
现在我们已经有了一些基本规则,让我们继续下一节,在那里我们将学习如何将所有这些内容合并到我们的自定义组件中。
将验证移入我们的自定义输入中
拥有自定义组件的惊人之处在于您可以以任何您喜欢的方式来打造它们。在本章中,我们将为我们的组件添加对有效和无效状态的支持。主要的验证逻辑仍将由父组件App.vue
持有,因为它是包含表单的组件。
按照以下步骤添加验证:
- 首先,让我们为每个输入添加新的规则。将以下内容添加到
validations
属性中:
validations: {
form: {
first_name: { alpha, required },
last_name: { alpha },
email: { email, required },
telephone: {
validPhone: phone => phone.match(/((\(\d{3}\) ?)|(\d{3}-))?
\d{3}-\d{4}/) !== null
},
website: { url },
love: { required }
}
},
- 不要忘记更新您的导入语句,以引入我们现在使用的新验证器,如下所示:
import { url, alpha, email, required } from 'vuelidate/lib/validators';
让我们来看看新的验证器:
-
alpha
:这将限制字段只能包含字母数字字符。 -
required
:此字段使字段成为必填项;如果没有值,则无效。 -
email
:此字段确保输入保持有效的电子邮件格式。
对于telephone
字段,我们将进行一些自定义验证,因为该字段被掩码为特定格式(###)###-####
,我们需要编写自己的验证函数。
在这种情况下,我们正在调用验证器validPhone
,它是一个返回布尔值的函数。这个布尔值是通过将电话与正则表达式进行匹配并确保它不为空来计算的;也就是说,它确实有一个匹配项。
现在我们已经将所有的validations
放在了适当的位置,我们需要更新我们的App.vue
模板。我们的BaseInput
组件和BaseSelect
组件需要更新v-model
,以便它指向 Vuelidate 模型而不是我们的本地状态。此外,我们需要将我们的网站输入更新为完整的BaseInput
组件。
- 对您的代码进行以下更改;我们正在更新
v-model
和输入类型:
<form>
<BaseInput
label="First Name:"
v-model="$v.form.firstName.$model"
/>
<BaseInput
label="Last Name:"
v-model="$v.form.lastName.$model"
/>
<BaseInput
label="Email:"
v-model="$v.form.email.$model"
type="email"
/>
<BaseInput
label="The URL of your favorite Vue-made website"
v-model="$v.form.website.$model"
/>
<BaseInput
label="Telephone"
type="text"
v-model="$v.form.telephone.$model"
:mask="'(###)###-####'"
/>
<BaseSelect
label="What do you love most about Vue?"
:options="loveOptions"
v-model="$v.form.love.$model"
/>
<div class="form-group">
<button
:disabled="!formIsValid"
@click.prevent="onSubmit"
type="submit"
class="btn btn-primary"
>Submit</button>
</div>
</form>
为了使我们的自定义组件显示正确的 CSS 类,我们将为它们添加一个名为validator
的新属性,并将引用传递给与特定元素匹配的 Vuelidate 对象的 prop。
- 打开
BaseInput.vue
并创建validator
属性,如下所示:
validator: {
type: Object,
required: false,
validator($v) {
return $v.hasOwnProperty('$model');
}
}
在属性的“验证器”方法中,我们将检查作为属性传递的“验证器”对象中是否有一个$model
属性(即“验证器.$model”),这对于 Vuelidate 的所有字段属性都是 true。这样,我们可以确保我们可以访问我们需要的属性。
接下来,让我们将之前在元素上的:class 绑定带过来,但我们会做一些小的调整,以适应这是一个组件属性。
- 将以下内容添加到 BaseInput.vue 中的元素:
:class="{
'is-valid': validator && !validator.$error && validator.$dirty,
'is-invalid': validator && validator.$error
}"
由于验证器不是我们组件上的必需属性,我们必须再次检查实际设置的条件,然后再检查它的\(error 和\)dirty 属性。
- 最后,回到 App.vue 并为所有的 BasicInput 元素添加:validator 属性:
<BaseInput
label="First Name:"
v-model="$v.form.firstName.$model"
:validator="$v.form.firstName"
/>
<BaseInput
label="Last Name:"
v-model="$v.form.lastName.$model"
:validator="$v.form.lastName"
/>
<BaseInput
label="Email:"
v-model="$v.form.email.$model"
:validator="$v.form.email"
type="email"
/>
<BaseInput
label="The URL of your favorite Vue-made website"
v-model="$v.form.website.$model"
:validator="$v.form.website"
/>
<BaseInput
label="Telephone"
type="text"
v-model="$v.form.telephone.$model"
:validator="$v.form.telephone"
:mask="'(###)###-####'"
/>
回到你的浏览器,玩弄一下输入框,现在它们都在后台由 Vuelidate 进行验证!
哇,这是相当多的信息 - 休息一下,吃点鳄梨土司;你值得拥有!在下一节中,我们将对我们的表单、BaseSelect 和 onSubmit 方法进行一些最终的更改,以便我们可以结束这一切。
添加最后的修饰
在我们结束本章之前,还有一些事情需要做。首先,让我们处理 BaseSelect;它仍然需要一个验证器属性和一些:class 绑定。
按照以下步骤找出我们如何做到这一点:
- 首先,在 BaseSelect.vue 中添加验证器属性:
validator: {
type: Object,
required: false,
validator($v) {
return $v.hasOwnProperty('$model');
}
}
现在,让我们添加:class 绑定;但这里,我们不会根据$dirty 进行检查,因为我们没有初始空值。
- 将以下代码添加到