一、web世界的经典元素 - 表单
说到表单我们就不得不提到验证,我们需要过滤掉一系列方法的输入,最早的时候这个功能一般是在服务器端完成,假如有错误服务器会返回并且渲染一些错误,这样做费时费力,所以说在现在的web应用中,表单一般会在前端进行验证,它会适时的展示用户的问题,当没问题时就发送请求,然后后端再验证一次,我们现在还没有接入后端,所以不需要考虑点击提交以后和后端的交互功能,而是只有一个关注点,那就是表单验证。
所谓表单验证是表单世界里前端最重要的一个功能,将表单验证的功能封装好也算是一个难点,接下来我们来一步步完成这个任务。
首先我们来分析一下,表单验证有怎样的功能点。我们把整个表单即一系列的input称为一个Form,每一项称为Item,这里面就有两项item,一个是用户名一个是密码。
拿单个Item来说,它应该有一系列的规则,它可以是多种类型的表单元素比如可以是input可以是checkbox等等,验证规则可以在某个事件触发的时候发生,比如这个Blur即当这个input框中失去焦点的时候会触发它的验证,每一个Item可以有多个验证的规则,可以称之为Rule如下。
除了每个Item单独验证以外,我们提交整个Form的时候,这个行为一般是点击提交按钮以后的行为,它会触发Form中的每一项Item的验证流程
二、ValidateInput - 简单的实现
上面我们已经明确了需求,就是把表单分为两部分,一个是单独的Item待特定的事件触发验证,另外一个是触发整个表单Form,在表单整体提交的时候触发每个Item的验证。
表单的样式我们到Bootstrap中去找
由于我们还没有做路由,所以我们先把App.vue中column-list去掉后面再加回来,然后我们引入Bootstrap中的Form表单样式,如下
样式有了,接下来我们就可以添加逻辑了,其实逻辑也不复杂,就是在input在Blur即失去焦点的时候来验证规则。
首先我们针对邮箱地址添加规则,这里我们暂时规定要验证两个规则,一个是不能为空,二是我们输入的文本要符合email的格式。
1、首先我们实现第一个规则即不能为空,如果为空则显示对应的错误信息
第一个我们要创建一个reactive对象,为什么要创建一个reactive对象呢,因为这个对象里要包括多个内容,一个要包括当前input当前值即val,第二要包括是否有error,第三是假如有error显示什么信息即message。
然后我们要创建一个函数,这是我们在失去焦点即Blur的时候要发生的回调函数,如下,如果emailRef.val去掉前后空格后为空,则我们让error置为true,让message为如下,然后html中如果emailRef.error为true则展示emailRef,message
通过v-model可以自动获得表单输入的双向绑定,是一个vue2经常使用的语法糖,即你表单里输入什么内容它val就会跟着变成什么内容,你val里变成什么内容,input输入框中就跟着变成什么内容
trim()即两边去掉空格
2、实现输入的文本要符合email的格式
我们在网上找到好用的判断email格式的正则表达式,直接拿过来使用
如下我们定义一个验证email的正则表达式叫emailReg,然后通过emailReg.test(rmailRef.val)来验证,如果是email格式则返回true否则返回false,所以如果为false说明不是email格式,那么我们就让它error为true,并且message为对应的文字提示
我们验证过程就是这样的,而且它可以展示两个完全不同的验证类型。
但是但我们想写第二个即密码的验证的时候,我们发现每个表单的验证基于不同的规则都是重复的,比如密码验证也是首先不能是空然后要符合密码的格式,就也差不多是这样。
所以我们可以尝试将这些基本的验证逻辑都总结成特定的规则,传入到单独的组件当中,然后根据这些规则快速完成这些表单项的验证。
三、ValidateInput - 抽象验证规则
现在我们把这个验证功能抽象成一个通用的组件。
这个组件的属性应该都有什么呢即这个组件应该接收什么呢,应该是规则,各种不同的规则,因为验证就是根据你传入的不同的规则对文本进行处理,自然每个规则就有它的类型
然后在App.vue中引入,且造出要给这个组件传入的rule
然后继续做这个失去焦点后的验证逻辑。
如下我们是要判断输入框中输入的文本是否符合规则,我们应该遍历所有的规则即输入框输入的文本要符合所有的规则才可以。所以通过every遍历props中的所有的规则;定义一个布尔值变量passed,如果符合这个规则就置为true如果不符合规则就置为false;同时把当前遍历的规则的message赋值给输入框的message
遍历规则的时候你可能当前是在required规则下(即输入框中不能为空),也可能在email规则下(即输入框中是文本需要符合email格式的正则表达式),你不确定当前遍历到的是哪个规则,所以我们用switch-case,如果当前遍历到的规则是required则走inputRef.val.trim()!==''的判断,如果当前遍历到的规则是email则走emailReg
然后我们给input框加上比如说不合规则的时候就把输入框显示红色
为空时:
不合电子邮箱格式时
这样我们就抽象出了validateInput这个组件,我们可以添加多种rules,然后进行判断,现在我们要创建需要验证的input就容易多了,我们只需要创建多个这种传入的rules就可以完成原来复杂重复的验证逻辑了。而且整个验证是可以扩展的,可以根据整个需求给它添加各种各样不同的规则。
四、ValidateInput - 支持v-model
说到input,我们都会想到v-model,它是一个双向绑定的工具,我们上面就用v-model获取了输入框中输入的值,就是子组件validateInput组件中我们通过给input输入框绑定v-model,就可以实现双向绑定,即输入框中数据和setup中响应式对象inputRef中的数据,一个改变会引起另一个的改变即双向绑定。但是这是一个组件内一个输入框和setup中数据的绑定。
但是现在有一个问题就是父组件App.vue中想拿到子组件这个输入框输入的值,父组件获取不到,比如我们想要在父组件获取子组件输入框的值进行下一步操作哦。
首先要知道vue具有单向数据流的特性,就是数据传递只是单向的。所有的prop都使得父子prop之间形成了一个单向下行绑定:父级prop的更新会向下流动到子组件中,但是反过来则不行。也就是父组件传给子组件的数据,子组件只能展示,不能修改,如果需要修改则需要emit事件让父组件修改。
我们要实现的效果是:父组件定义的值 和 子组件的输入框 想实现双向绑定。也就是子组件的输入框绑定父组件传递过来的值,而子组件的输入框的值改变后,父组件这个值也会跟着改变
简单来说就是父组件定义的这个值改变的话,子组件输入框的值也跟着改变;子组件输入框的值改变的话,父组件定义的这个值也跟着改变。
这里就需要用到自定义组件的v-model这个知识点了。
子组件输入框使用v-model绑定父组件传递的值,输入框数据更新后再传回给父组件。
实现思路就分两步走:
第一步,子组件中,在props中创建modelValue,然后在输入框中数据更新的时候需要发送事件,这个事件名称就叫update:modelValue,这样就可以实现v-model的功能啦
如上绑定一个value=inputRef.val,并且绑定input事件;然后在props中创建modelValue;然后定义输入框更新的事件即updateValue,事件中e:KeyboardEvent指键盘事件,通过e.target去获取输入框里的值,然后此时输入框中的数据是改变了的,所以我们把改变的新值赋值给inputRef.val,最后定义emit事件去调用update:modelValue事件从而改变父组件中绑定的对应值。
第二步,父组件中,定义要传给子组件输入框的值,然后在该子组件标签中通过v-model绑定该值
五、ValidateInput - 使用 $attrs 支持默认属性
在input上面有很多原生属性,比如说type,它可以创建不同类型的input,比如说placeholder,它是提示用户输入框的作用
最后加上密码: