阅读 377

组件化开发 | vue3+ts封装Input组件(组件化开发和模块化开发)

前言

在组件化开发中,输入框组件在开发中也是一个常用的组件之一,但是每次单独为每一个input输入框添加样式、校验规则等有些繁琐,也不利于维护管理,那么这篇文章将用来记录学习封装带校验规则的ValidateInput输入框。实现的功能有:

  1. 支持自定义校验规则

  2. 校验效果及时反馈

  3. 父子组件数据双向绑定

另外一些可自定义的参数/api,例如占位符placeholderfocuschange可由需求扩展

自定义校验规则接口

这里以required必须项和email邮箱校验规则为例,并且需要一个校验失败的提示信息message

interface RuleProp = {   type: 'required' | 'email';   message: string; } export type RulesProp = RuleProp[] 复制代码

自定义ValidateInput组件

将输入的值动态绑定到inputRef.val,在输入框失焦blur时执行校验,并在校验失败后将反馈信息inputRef.message展示在提示框中

<template>   <div class="validate-input-container pb-3">     <input       type="text"       v-model="inputRef.val"       class="form-control"       @blur="validateInput"     />     <div v-if="inputRef.error" class="form-text">       {{ inputRef.message }}     </div>   </div> </template> <script lang="ts"> import { defineComponent, PropType, reactive } from 'vue' interface RuleProp {   type: 'required' | 'email';   message: string; } const emailReg = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/  // 验证邮箱 export type RulesProp = RuleProp[] export default defineComponent({   props: {     rules: Array as PropType<RulesProp>,     modelValue: String   },   setup(props, context) {     const inputRef = reactive({       val: '',       error: false,       message: ''     })     const validateInput = () => {       if (props.rules) {         const allPassed = props.rules.every((rule) => {           let passed = true           inputRef.message = rule.message           switch (rule.type) {             case 'required':               passed = inputRef.val.trim() !== ''               break             case 'email':               passed = emailReg.test(inputRef.val)               break             default:               break           }           return passed         })         inputRef.error = !allPassed       }     }     return {       inputRef,       validateInput,       updateValue     }   } }) </script> 复制代码

调用时传入校验规则

const emailRules: RulesProp = [   { type: 'required', message: '邮箱不能为空' },   { type: 'email', message: '请输入正确的邮箱格式' } ] <validate-input :rules="emailRules" /> 复制代码

效果:

image.png

样式上与我们平时遇到的校验格式有很大出入,不过这些会在后面补上

组件数据双向绑定

到目前为止我们的input框有一个问题是:父组件不能拿到ValidateInput框内输入的内容,不能做到使用v-model双向绑定数据。我们都知道v-model的原理是通过v-bind绑定一个value值,结合@input事件动态改变绑定的value值实现数据双向绑定,那么我们在组件中我们也可以通过这个原理在组件间实现数据双向绑定

我们要知道在父组件中传入v-model的值,在子组件中是通过modelValue接收的

  1. ValidateInput通过modelValue接收父组件v-model绑定的值

// 子组件 props: {   rules: Array as PropType<RulesProp>,   modelValue: String; } 复制代码

  1. 给input框绑定value值和@input事件

<template>   <div class="validate-input-container pb-3">     <input       type="text"       class="form-control" +     :value="inputRef.val" +     @input="updateValue"       :placeholder="placeholder"       @blur="validateInput"     />   </div> </template> 复制代码

  1. 发射事件通知父组件修改v-model的值

const updateValue = (e: Event) => {   const targetValue = (e.target as HTMLInputElement).value   inputRef.val = targetValue   context.emit('update:modelValue', targetValue) } 复制代码

整个过程我用下面这个图表示出来,其实就是一个父子组件通信的过程,这是因为子组件不能直接修改props值(props值只负责传递数据),而是需要通知父组件修改传过来的props值,进行数据更新,再拿到修改后的值。

image.png

自定义校验用户名的输入框

通过给ValidateInput加上校验成功/失败后的样式,来达到及时给用户反馈校验后信息的效果

<template>   <div class="validate-input-container pb-3">     <input       type="text"       class="form-control"       v-model="inputRef.val"       @blur="validateInput"       :class="{ 'is-invalid': inputRef.error, 'is-valid': !inputRef.error }"     />     <span v-if="inputRef.error" class="invalid-feedback">       {{ inputRef.message }}     </span>     <span v-if="inputRef.success" class="valid-feedback"> yes </span>   </div> </template> 复制代码

<template>   <div class="validate-input-container pb-3">     <input       type="text"       class="form-control"       v-model="inputRef.val"       :placeholder="placeholder"       @blur="validateInput"       :class="{ 'is-invalid': inputRef.error, 'is-valid': inputRef.success }"     />     <span v-if="inputRef.error" class="invalid-feedback">       {{ inputRef.message }}     </span>   </div> </template> <script lang="ts"> import { defineComponent, PropType, reactive } from 'vue' interface RuleProp {   type: 'required' | 'email' | 'username' | 'only'   message: string } const emailReg = /^1[3|4|5|7|8][0-9]{9}$/ const usernameReg = /......./    // 这里写入用户名的正则表达式 export type RulesProp = RuleProp[] export default defineComponent({   props: {     placeholder: String,     rules: Array as PropType<RulesProp>   },   setup(props) {     const emailRules: RulesProp = [       { type: 'required', message: '用户名不能为空' },       { type: 'username', message: '请输入正确格式的用户名' },       { type: 'only', message: '用户名已存在' }     ]     const inputRef = reactive({       val: '',       success: true,       error: false,       message: ''     })     const validateInput = () => {       if (props.rules) {         const allPassed = props.rules.every((rule) => {           let passed = true           inputRef.message = rule.message           switch (rule.type) {             case 'required':               passed = inputRef.val.trim() !== ''               break             case 'username':               passed = usernameReg.test(inputRef.val)               break             case 'only':               // 校验用户名是否存在             default:               break           }           return passed         })         inputRef.error = !allPassed         inputRef.success = allPassed       }     }     return {       inputRef,       validateInput     }   } }) </script> 复制代码

image.png


作者:alexis
链接:https://juejin.cn/post/7027833439667617829


文章分类
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐