当前位置: 首页 > Web前端 > vue.js

使用VueCompositionAPI编写简洁、可扩展的表单

时间:2023-04-01 11:26:42 vue.js

表单是前端开发中最棘手的部分之一,您可能会在其中找到很多混乱的代码。基于组件的框架,比如Vue.js,在提高前端代码的可扩展性方面做了很多工作,但是表单的问题依然存在。在本教程中,我将向您展示新的VueCompositionAPI(即将在Vue3中推出)如何使表单代码更清晰、更可扩展。为什么表单代码经常很糟糕Vue等基于组件的框架中的一个关键设计模式是组件组合。此模式将应用程序功能抽象为独立的、单一用途的组件,这些组件使用道具和事件进行通信。然而,在这种模式中,表单并没有被很好地抽象,因为表单的功能和状态显然不属于任何一个组件,所以将它们分开往往会导致与其解决的问题一样多的问题。表单代码用Vue写的不好的另一个重要原因是,在Vue2之前,还没有强大的手段来重用组件之间的代码。重用代码对于表单很重要,因为表单输入通常明显不同,但在功能上有许多相似之处。Vue2提供的代码重用的主要方式是mixins,我认为这是一个明显的反模式。MixinsConsideredHarmful早在2016年年中,DanAbramov写了《mixin被认为是有害的》(mixinConsideredHarmful),他在文中认为mixins在React组件中用于复用逻辑是一种反模式,提倡远离它们。不幸的是,他提到的关于Reactmixin的缺点也适用于Vue。在了解CompositionAPI如何克服它们之前,让我们先熟悉一下这些缺点。命名冲突使用混合模式在运行时合并两个对象,如果它们共享同名属性会怎样?constmixin={data:()=>({myProp:null})}exportdefault{mixins:[mixin],data:()=>({//同名!myProp:null})}这是合并策略在它起作用的地方发挥作用。这是一组规则,用于确定当组件包含多个同名选项时会发生什么。Vue组件的默认(可选配置)合并策略规定本地选项将覆盖混合选项。但也有例外,例如,如果我们有多个相同类型的生命周期钩子,这些钩子将被添加到一个钩子数组中,并且所有钩子将被顺序调用。虽然我们不应该遇到任何实际的错误,但编写处理跨多个组件和混合的命名属性的代码变得越来越困难。一旦将第三方mixins添加为具有自己的命名属性的npm包,就特别困难,因为它们会导致冲突。隐式依赖的mixin和使用它的组件之间没有层次关系。这意味着组件可以使用mixins中定义的数据属性(例如mySharedDataProperty),但是mixins也可以使用组件中定义的数据属性(例如myLocalDataProperty)。当mixin用于共享输入验证时,通常会出现这种情况,mixin可能期望组件具有将在其自己的验证方法中使用的输入值。但是,这可能会导致一些问题。如果我们稍后想要重构一个组件并更改mixin所需的变量名称,会发生什么情况?当我们查看这个组件时,我们找不到任何问题。代码检查也不会发现它,您只会在运行时看到错误。现在想象一个有很多mixins的组件。我们可以重构本地数据属性吗?或者它会破坏mixins吗?我们必须进行手动搜索才能找到答案。mixins的缺点是CompositionAPI背后的主要激励因素之一,让我们看看它如何克服mixins的问题以编写干净、可扩展的表单代码。将VueCompositionAPI添加到Vue2项目通过VueCLI创建一个项目,并将CompositionAPI作为插件添加到Vue2项目。$vuecreatecomposition-api-form$cdcomposition-api-form$npmi-S@vue/composition-api接下来,将这个插件添加到main.jsimportVuefrom"vue";importAppfrom"./App.vue";importVueCompositionApifrom"@vue/composition-api";Vue.use(VueCompositionApi);newVue({render:h=>h(App)}).$mount('#app');创建输入component为了简化这个例子,我们将创建一个单独的组件,它只包含输入名称和电子邮件。$touchsrc/components/InputName.vue$touchsrc/components/InputEmail.vue设置InputName组件模板,包含一个HTML输入元素,并使用v-model指令创建双向绑定。src/components/InputName.vue设置表单将添加novalidate属性,让浏览器知道我们将提供自定义验证。它还会监听表单的提交事件,防止表单自动提交,并使用声明的onSubmit方法处理该事件。然后,添加InputName和InputEmail组件,分别绑定本地状态值name和email。src/App.vue接下来,使用CompositionAPI定义表单函数。在组件定义中添加setup方法,使用CompositionAPI提供的ref方法声明两个状态变量name和email。然后声明一个onSubmit函数来处理表单提交。src/App.vue//省略其余部分...import{ref}from"@vue/composition-api";exportdefault{name:"App",setup(){constname=ref("");const电子邮件=ref("");functiononSubmit(){//这里可以写提交后台的逻辑console.log(name.value,email.value);}return{name,email,onSubmit}},...}settings输入组件接下来,定义InputName组件的功能。在组件上使用v-model指令创建与组件的双向绑定,在组件内部的props上定义值以接收值,这只完成了一半的工作。创建设置函数。props和组件实例被传递到这个方法中,使我们能够访问组件实例上的方法。以解构的方式获取第二个参数中的emit方法。您将需要它来完成v-model双向绑定的另一半,即触发输入事件和修改绑定值。在此之前,声明一个状态变量输入,它将绑定到我们在模板中声明的HTML元素。该变量的值是要定义的合成函数useInputValidator执行后返回的值。此函数将处理所有常用的验证逻辑。将prop.value作为第一个参数传递给这个方法,第二个参数是一个回调函数,接收验证后的输入值,在这个回调函数中触发输入事件,修改v-model绑定的值,实现的功能与父组件的双向绑定。src/components/InputName.vue输入框验证函数开始创建useInputValidator组合函数,为此首先创建一个features文件夹,并为其创建一个模块文件。$mkdirsrc/features$touchsrc/features/useInputValidator.js在模块文件中,将导出一个带有两个参数的函数:从父表单接收的值,通过startVal接收;和一个回调函数,通过onValidate接收。该函数需要返回一个输入状态变量,因此需要通过调用ref并提供startVal的值来声明、初始化它。在从函数返回输入之前,观察值变化并调用onValidate回调,传入最新的输入值。src/features/useInputValidator.jsimport{ref,watch}from"@vue/composition-api";导出默认函数(startVal,onValidate){letinput=ref(startVal);观看(输入,价值=>{onValidate(价值);});return{input}}添加验证器下一步是添加验证器函数。对于InputName组件,只有一个验证规则minLength,它确保输入的是三个字符或更多。尚未创建的InputEmail组件将需要电子邮件验证规则。将在src文件夹中创建模块validators.js并编写这些验证器。在实际项目中,您可能会使用第三方库。我不会深入验证器函数的细节,但有两件重要的事情需要注意:这些是返回函数的函数。这样的结构允许我们通过传递成为闭包一部分的参数来自定义验证规则。每个验证器返回的函数总是返回一个字符串(错误消息),如果没有错误则返回null。src/validators.jsconstminLength=min=>{returninput=>input.length{constre=/\S+@\S+\.\S+/;返回输入=>重新测试(输入)?null:"必须是有效的电子邮件地址";}export{minLength,isEmail};返回上面组合函数所在的文件,useInputValidator.js,我们要使用需要的校验,在函数中再增加一个参数,就是校验函数的数组。在输入监视器内部,使用数组的map方法调用验证函数,将输入的当前值传递给每个验证器方法。返回值将被捕获到一个新的状态变量errors中,它也将被返回给宿主组件使用。src/features/useInputValidator.jsexport默认函数(startVal,validators,onValidate){constinput=ref(startVal);常量错误=ref([]);watch(input,value=>{errors.value=validators.map(validator=>validator(value));onValidate(value);});return{input,errors}}最后回到InputName组件,现在将为useInputValidator方法提供所需的三个参数。第二个参数现在是一个验证器数组,所以让我们就地声明一个数组并将其传递给minLength方法。minLength是一个工厂函数,调用并传递指定的最小长度。现在我们还从复合函数返回的对象中获取输入和错误,这两者都将从设置方法返回以在组件中可用。src/components/InputName.vue//省略其他代码...import{minLength}from"@/validators";importuseInputValidatorfrom"@/features/useInputValidator";exportdefault{...setup(props,{emit}){const{input,errors}=useInputValidator(props.value,[minLength(3)],value=>emit("input",value));return{input,errors}}}这是我们要添加到组件的最后一个函数。在我们继续之前,花点时间比较一下这段代码的可读性比使用mixin高多少。首先,您可以清楚地看到声明和修改状态变量的位置,而无需切换到单独的mixin模块文件。此外,您不必担心局部变量和复合函数之间的名称冲突。显示错误进入InputName组件的模板,它有一个要显示的潜在错误数组,委托给一个名为ErrorDisplay的组件来显示错误。src/components/InputName.vueErrorDisplay组件基于业务需要,可以自己定制。代码复用这是我们基于CompositionAPI编写的表单的基本功能。本教程的目标是创建简洁且可扩展的表单代码,我们将通过定义InputEmail组件来证明我们已经做到了这一点。src/components/InputEmail原文:https://vuejsdevelopers.com/2...参考:https://css-tricks.com/how-th...github博客地址:https://github.com/WYseven/bl....如果对你有帮助,请关注【前端技能解锁】:

最新推荐
猜你喜欢