赞
踩
表单是前端开发中最棘手的部分之一,您可能会在其中发现很多混乱的代码。
Vue.js 2之类的基于组件的框架在提高前端代码的可伸缩性方面做了很多工作,但是形式问题仍然存在。
在本教程中,我将向您展示新的Vue Composition API(属于Vue 3)将如何使您的表单代码更加整洁和可扩展。
像Vue这样的基于组件的框架的关键设计模式是组件组合。该模式告诉我们将应用程序的特性抽象为独立的、单一用途的组件,这些组件使用属性和事件来进行状态通信。
然而,在这种模式下,表单不能被很好地抽象出来,因为表单的功能和状态并不明显属于任何一个组件,因此将其分离常常会导致与它所解决的问题一样多的问题。
直到Vue 2为止,Vue都不具备在组件之间重用代码的强大方法。这在表单中很重要,因为表单输入通常明显不同,但在功能上有许多相似之处。
Vue 2提供的代码重用的主要方法是mixin,许多人认为这是公然的反模式。
Composition API是使用Vue.js定义组件的新方法,它将成为Vue 3的核心功能。它现在也可以在Vue 2中作为插件使用。
这个新的API旨在解决我提到的一些问题(不仅在形式上,而且在前端应用程序架构的任何方面)。
如果您对Composition API还是不熟悉,或者不清楚它的用途,建议您先阅读文档,以及我写的另一篇文章《何时使用新的Vue Composition API(何时不使用)》。
以及我制作的Vue3 Composition API 备忘单,私信回复:“vue3”获取
Composition API不能替代经典的Vue API,而是可以在需要时使用的东西。正如您将在本文中看到的那样,创建干净且可伸缩的表单代码是一个完美的用例。
由于我是在Vue 3发布之前编写本教程的,所以让我们将Composition API作为插件添加到Vue 2项目中。
$ vue create composition-api-form$ cd composition-api-form$ npm i -S @vue/composition-api
接下来,让我们将插件添加到main.js中的Vue实例中。
import Vue from "vue";import App from "./App.vue";import VueCompositionApi from "@vue/composition-api";Vue.use(VueCompositionApi);new Vue({ render: h => h(App)}).$mount('#app');
为了使这个例子简单,我们将创建一个仅包含两个输入的表单——名称和电子邮件。让我们将它们创建为自己的独立组件。
$ touch src/components/InputName.vue$ touch src/components/InputEmail.vue
现在让我们以典型的方式设置InputName组件模板,其中包括带有 v-model 指令的HTML输入元素,该模板与该组件创建双向绑定。
src/components/InputName.vue
Name
让我们暂时把输入放在一边,然后设置表单。您可以将其作为一个单独的组件来创建,以使其可重用,但是为了本教程的简单性,我将在App组件模板中声明它。
我们将添加 novalidate 属性,以使浏览器知道我们将提供自定义验证。我们还将监听表单的 submit 事件,阻止其自动提交,并使用稍后将声明的 onSubmit 方法处理该事件。
然后,我们将添加 InputName 和 InputEmail 组件,并分别将本地状态值 name 和 email 绑定到它们。
src/App.vue
Submit
现在让我们使用Composition API定义表单功能。我们将向组件定义添加一个 setup 方法,在这个方法中,我们将使用Composition API的 ref 方法声明两个状态变量 name 和 email。这个方法需要从Composition API包中导入。
然后,我们将声明一个 onSubmit 函数来处理表单提交。我不会指定任何功能,因为它与本教程无关。
最后,我们需要返回从 setup 函数创建的两个状态变量和方法,以便组件的模板可以访问它们。
src/App.vue
...import { ref } from "@vue/composition-api";export default { name: "App", setup () { const name = ref(""); const email = ref(""); function onSubmit() { // 提交到后端或任何你喜欢的 console.log(name.value, email.value); } return { name, email, onSubmit } }, ...}
接下来,我们将定义 InputName 组件的功能。
由于父表单对这个组件使用的是 v-model,重要的是声明了一个prop值,该值将是双向绑定功能实现的一部分(一半)。
让我们创建一个 setup 函数,将props传递到这个方法中,从而使我们能够访问组件实例方法。我们可以解构第二个参数并获得 emit 方法。我们将需要它来完成 v-model 双向绑定的另一半,也就是说,响应地发出input的新值。
在此之前,让我们声明一个状态变量 input,它将绑定到我们在模板中声明的input HTML元素。
这个变量的值是我们将要定义的composition function(复合函数) useInputValidator 中返回的值。这个函数将处理所有常见的验证逻辑。
我们将把值prop传递给这个方法,第二个参数是一个回调函数,它返回经过验证的输入值。让我们使用这个回调来将这个输入作为事件发出,并实现 v-model 契约。
import useInputValidator from "@/features/useInputValidator";export default { name: "InputName", props: { value: String }, setup (props, { emit }) { const { input } = useInputValidator( props.value, value => emit("input", value) ); return { input } }}
现在让我们创建 useInputValidator 合成函数。为此,我们将首先创建一个 features 文件夹,然后为其创建一个模块文件。
$ mkdir src/features$ touch src/features/useInputValidator.js
在模块文件中,我们导出一个函数,我们刚刚看到它将需要两个参数——从父窗体接收到的 value prop(我们将其称为 startVal)和将被称为 onValidate 的回调方法。
请记住,这个函数需要返回一个 input 状态变量,因此让我们来声明它,分配一个用prop提供的初始值的ref。
在从函数返回 input 值之前,让我们看一下它的值,并使用input作为参数调用 onValidate 回调。
src/features/useInputValidator.js
import { ref, watch } from "@vue/composition-api";export default function (startVal, onValidate) { let input = ref(startVal); watch(input, value => { onValidate(value); }); return { input }}
下一步是添加验证器功能,对于 InputName 组件,我们只有一个验证规则——minLength,确保输入为三个或更多字符。尚未创建的 InputEmail 组件将需要电子邮件验证。
现在,我们将在src/validateators.js中创建这些验证器。在实际的项目中,您可能会改用第三方库。
不会详细介绍验证器功能,但需要注意以下两点:
src/validators.js:
const minLength = min => { return input => input.length < min ? `Value must be at least ${min} characters` : null;};const isEmail = () => { const re = /S+@S+.S+/; return input => re.test(input) ? null : "Must be a valid email address";}export { minLength, isEmail };
回到复合函数中,我们希望组件消费者定义它所需要的验证,因此,让我们首先向 validators 中添加另一个参数,该参数应该是验证函数的数组。
在input watcher 内部,我们现在将处理验证功能。让我们使用验证器数组的 map 方法,将输入的当前值传递给每个验证器方法。
返回值将被捕获到一个新的状态变量 error 中,我们还将返回到组件使用方。
src/features/useInputValidator.js:
export default function (startVal, validators, onValidate) { const input = ref(startVal); const errors = ref([]); watch(input, value => { errors.value = validators.map(validator => validator(value)); onValidate(value); }); return { input, errors }}
最后回到 InputName 组件,我们现在将为 useInputValidator 方法提供所需的三个参数。记住,第二个参数现在是一个验证器数组,所以让我们就地声明一个数组,并传入 minLength,我们将从验证器文件中导入该代码。
minLength 是一个工厂函数,因此我们调用传递我们想要指定的最小长度的函数。
现在,我们还从合成函数返回了两个对象——input和error。两者都将从 setup 方法返回,以在组件的渲染上下文中提供可用性。
src/components/InputName.vue
...import { minLength } from "@/validators";export default { ... setup (props, { emit }) { const { input, errors } = useInputValidator( props.value, [ minLength(3) ], value => emit("input", value) ); return { input, errors } }}
这是我们将添加到此组件的最后一个功能。不过,在继续之前,请花点时间了解一下此代码比我们使用mixin所看到的代码更具可读性,这一点很重要。
一方面,我们清楚地看到了状态变量的声明和修改位置,而无需浏览到单独的mixin模块文件。另一方面,我们不必担心局部变量和组合函数之间的名称冲突。
转到 InputName 组件模板,现在可以显示一系列潜在的错误。让我们将其委托给一个名为 ErrorDisplay 的显示组件。
Name
ErrorDisplay 的功能太简单了,这里就不显示了。
这就是我们基于Composition API 表单的基本功能。本教程的目标是创建干净的、可伸缩的表单代码,我想通过定义我们的第二个自定义输入 InputEmail 向您证明这一点。
如果您达到了本教程的目标,那么在没有我的说明情况下,您可以毫无困难地理解它!
src/components/InputEmail
Email
完整源代码,请私信回复:“vue3-form”
如果对你有所启发和帮助,可以点个关注、收藏,也可以留言讨论,这是对作者的最大鼓励。
作者简介:Web前端工程师,全栈开发工程师、持续学习者。
现在关注《前端外文精选》公众号,送精品视频视频教程大礼包!
#Vue.js#
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。