清远专业网站建设服务,网站建设合同用贴印花税吗,手机开网店,网络优化案例分析之前一直是直接去使用别人现成的组件库#xff0c;也没有具体去了解人家的组件是怎么封装的#xff0c;造轮子才会更好地提高自己#xff0c;所以尝试开始从封装Form表单组件开始 一#xff1a;组件需求分析 本次封装组件#xff0c;主要是摸索封装组件的流程#xff0c;… 之前一直是直接去使用别人现成的组件库也没有具体去了解人家的组件是怎么封装的造轮子才会更好地提高自己所以尝试开始从封装Form表单组件开始 一组件需求分析 本次封装组件主要是摸索封装组件的流程对于具体需要的方法和属性只会实现其中部分方法和属性之后一点一点才进行添加 表单项组件ValidateInput组件的封装 根据传递不同的type类型有着不同的校验规则支持V-model对于封装的自定义组件支持v-model双向绑定也是一个很关键的属性tag根节点的类型 form组件提交事件 验证整体表单项是否通过清空表单项的内容
二技术栈
Vue3TSBootstrap样式库
三封装Validate-input验证表单项组件
思路
1. 明确属性和事件
v-model属性rules属性根据不同type不同校验规则tag根节点类型
ValidateInput组件
templatediv classvalidate-input-container pb-3inputclassform-control:class{ is-invalid: inputRef.error }:valuemodelValueblurvalidateInputinputupdateValuev-bind$attrs/span v-ifinputRef.error classinvalid-feedback{{ inputRef.message }}/span/div
/templatescript setup langts
//禁用 Attributes 继承
defineOptions({inheritAttrs: false
})
//定义传来的一个参数类型
interface RangeProp {message: stringlength: number
}
interface RuleProp {type: required | email | rangemessage?: string//至少位数min?: RangePropmax?: RangeProp
}
//数组类型
export type RulesProp RuleProp[]
//接收参数
const props defineProps{rules?: RulesProp//自定义组件使用v-model需要用modelValue来接收参数modelValue: string
}()//定义表单的数据
const inputRef reactive({//如果为空val: props.modelValue || ,error: false, //表单验证是否通过message: //错误信息
})
/script禁用Attributes继承透传 attribute”指的是传递给一个组件却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。 !-- MyButton 的模板 --
buttonclick me/button当父组件使用该组件并且传入class: MyButton classlarge /最终会在根元素出现class‘large“MyButton 并没有将 class 声明为一个它所接受的 prop所以 class 被视作透传 attribute自动透传到了 MyButton 的根元素上。 因此需要禁用Attibutes继承 定义接收参数类型 rules可选参数接收数组modelValue接收字符串即输入的值
2. v-model属性
在使用一个自定义组件给其添加v-model属性其自定义组件内部做了两件事
将内部原生的input元素的值绑定到组件内部Prop属性modelValue当原生input元素触发时候触发一个携带了新值的 update:modelValue 自定义事件 !-- 自定义组件Validate-input --Validate-input v-modelloginParams.email :rulesemailRules placeholder请输入邮箱地址/Validate-inputValidate-input组件
//接收参数
const props defineProps{rules?: RulesProp//自定义组件使用v-model需要用modelValue来接收参数modelValue: string
}()props接收了modelValue属性类型string inputclassform-control:class{ is-invalid: inputRef.error }:valuemodelValueblurvalidateInputinputupdateValuev-bind$attrs/设置了自定义事件用于更新value //手动更新value
const updateValue (e: Event) {//HTMLInputElement输入元素类型let targetValue (e.target as HTMLInputElement).value//更新文本框的值inputRef.val targetValueemit(update:modelValue, targetValue)
}因此实现v-model属性 3. rules属性
接收参数 type校验类型requied | email | rangemessagemin至少几位max至多几位
抽象验证逻辑
validate-input组件
//数组类型
export type RulesProp RuleProp[]
//接收参数
const props defineProps{rules?: RulesProp//自定义组件使用v-model需要用modelValue来接收参数modelValue: string
}()参数接收rules是个数组 //定义表单的数据
const inputRef reactive({//如果为空val: props.modelValue || ,error: false, //表单验证是否通过message: //错误信息
})定义表单的数据 //定义事件
const validateInput () {//定义邮箱的正则let emailReg /^[a-zA-Z0-9._-][a-zA-Z0-9.-]\.[a-zA-Z]{2,4}$///如果传过来的有验证的话if (props.rules) {//every方法 遍历全部数组只有全部满足条件才会返回true 只要有一个false停止遍历let allRulePassed props.rules.every(rule {let passed true//消息赋值 类型断言inputRef.message rule.message as string//switch选择对应type类型错误进行校验switch (rule.type) {case required:if (inputRef.val.trim() ) {passed false}breakcase email:if (!emailReg.test(inputRef.val)) {passed false}breakcase range:passed validateRange(rule.min, rule.max)break}return passed})//allRulePassed为false表示通过//所以Input.error表示错误应该为trueinputRef.error !allRulePassedreturn allRulePassed}return true
}定义校验事件 满足全部rules校验才可以通过因此用到es6数组方法every只有全部项都为true才会遍历全部返回true只要有一个项结果为false就会停止遍历 message校验信息赋值给inputRef.message 利用swicth case语句选择对应的type类型进行校验 需要充分考虑到所有情况通过passed为true未通过为fasle range长度校验由于情况较多单独封装一个函数去校验 //校验长度
const validateRange (min: RangeProp | undefined, max: RangeProp | undefined) {let passed true//1. 如果min 存在 ,max不存在if (min !max) {inputRef.message min.messagepassed !(inputRef.val.length min.length)}//2. min不在, max在if (!min max) {inputRef.message max.messagepassed !(inputRef.val.length max.length)}//3. min在 max在if (min max) {//若小于if (inputRef.val.length min.length) {passed falseinputRef.message min.message}//若大于if (inputRef.val.length max.length) {passed falseinputRef.message max.message}}return passed
}模板中根据passed的值动态绑定未通过的样式
4. 默认属性
validate-input组件 div classvalidate-input-container pb-3inputclassform-control:class{ is-invalid: inputRef.error }:valuemodelValueblurvalidateInputinputupdateValuev-bind$attrs/span v-ifinputRef.error classinvalid-feedback{{ inputRef.message }}/span/div父组件 Validate-inputv-modelloginParams.password:rulespasswordRulestypepasswordplaceholder请输入密码/Validate-input通过显示绑定attrs使得自定义组件可以使用默认属性 在ValidateInput组件中可以通过$attrs属性将type属性将被传递到组件的根元素上 可以在父组件中灵活地传递任何HTML属性给ValidateInput组件使它更加通用和可配置
四封装Validate-Form组件
事件 form-submit点击提交触发的事件回调参数result是布尔值表示该表单是否通过了校验
1. form-submit事件
当点击提交时要去验证该表单是否通过了校验就需要一个个将表单项进行校验只要一个没通过就返回false只有全部通过返回true
收集全部表单项校验函数
可以通过将所有表单项的校验函数都添加到一个数组中然后最终通过every方法遍历是否全部通过
收集
安装mitt并使用监听事件
npm install mitt --save全局挂载
main.ts
import mitt from mitt
//对外暴露全局事件总线实例
export const bus mitt()ValidateForm组件中使用
script setup langts
import { onUnmounted, reactive } from vue
import { bus } from /main
const emits defineEmits([form-submit])
//点击事件
//定义函数类型
type ValidateFunc () boolean
//定义类型
//定义接收的函数数组
const funcArr reactiveValidateFunc[]([])
//测试回调
const callback (func: ValidateFunc) {//将每个校验函数加入数组funcArr.push(func)
}
//订阅事件
bus.on(form-item-created, callback as ValidateFunc)//提交按钮触发事件
const submitForm () {const result funcArr.map(func func()).every(result result)// 触发提交事件//遍历funcArr中的每个校验函数emits(form-submit, result)
}
onUnmounted(() {// 移除订阅bus.off(form-item-created, callback as ValidateFunc)
})
/script定义函数类型返回值为空利用泛型定义存放每个表单项校验函数存放的数组订阅事件在组件卸载的时候再取消订阅
ValidateInput组件中
组件挂载的时候就直接触发自定义事件然后将每一项的校验函数传递给ValidateForm组件中
Validate-Form组件
然后接受ValidateInput组件传递过来的校验函数一个个加入到数组中在submitForm事件中遍历数组不能直接使用every方法因为只要一个不通过就不进行后面的校验这是不满足我们的需求的 可以看到下面的错误实例密码原本也是不通过校验的但是every方法直接在第一个校验失败结束遍历了 因此先利用map函数先使得每个校验函数都执行结束后返回一个新的数组存放校验函数的返回值再通过every遍历数组最后触发自定义事件将结果传递给父组件中
父组件
Validate-Form form-submitsubmitForm refvalidateFormRefconst submitForm (result: boolean) {console.log(result)
}提交表单元素后清空表单值
具体逻辑跟校验差不多
Validate-Form组件
script setup langts
import { onUnmounted, reactive } from vue
import { bus } from /main
const emits defineEmits([form-submit])
//点击事件
//定义函数类型
type ValidateFunc () boolean
//定义清空Input函数类型
type clearInputsFunc () void
//定义类型
//定义接收的函数数组
const funcArr reactiveValidateFunc[]([])
//定义接收用于清空的函数数组
const clearFuncArr reactiveclearInputsFunc[]([])
//测试回调
const callback (func: ValidateFunc) {//将每个校验函数加入数组funcArr.push(func)
}
//事件回调
const clearInputFunc (func: clearInputsFunc) {clearFuncArr.push(func)
}
//绑定监听事件
bus.on(form-item-created, callback as ValidateFunc)
bus.on(form-item-clear, clearInputFunc as clearInputsFunc)//提交按钮触发事件
const submitForm () {const result funcArr.map(func func()).every(result result)// 触发提交事件//遍历funcArr中的每个校验函数emits(form-submit, result)//遍历清空函数数组并依次并执行//当校验通过时候才会清空inputif (result) {clearFuncArr.map(func func())}
}
onUnmounted(() {// 移除事件监听器bus.off(form-item-created, callback as ValidateFunc)bus.off(form-item-clear, clearInputFunc as clearInputsFunc)
})
/scriptValidate-input组件 onMounted(() {//直接把validateInput校验事件传递过去bus.emit(form-item-created, validateInput)//直接触发事件先传入每个input的值bus.emit(form-item-clear, clearInput)
})//定义表单的数据
const inputRef reactive({//如果为空val: props.modelValue || ,error: false, //表单验证是否通过message: //错误信息
})把清空表单数据的处理函数收集起来最后利用map方法依次执行清除即可
五演示和使用 在 vue template 中添加结构代码 Validate-Form form-submitsubmitForm refvalidateFormRef!-- 邮箱地址 --div classmb-3label forexampleInputEmail1 classform-label邮箱地址/label!-- 自定义组件Validate-input --Validate-input v-modelloginParams.email :rulesemailRules placeholder请输入邮箱地址/Validate-input/div!-- 密码 --div classmb-3label forexampleInputPassword1 classform-label密码/labelValidate-inputv-modelloginParams.password:rulespasswordRulestypepasswordplaceholder请输入密码/Validate-input/divtemplate #submitbutton typesubmit classbtn btn-primary btn-block btn-large提交/button/template/Validate-Form在 setup语法糖中添加数据
//定义验证类型数据
const emailRules: RulesProp [{ type: required, message: 电子邮箱地址不能为空 },{ type: email, message: 请输入正确的电子邮箱格式 }
]
//定义密码验证类型数据
const passwordRules: RulesProp [{ type: required, message: 密码不能为空 },{type: range,min: { message: 你的密码至少包括6位,不能含有空格, length: 6 },max: {message: 你的密码至多15位,不能含有空格,length: 15}}
]//监听结果
const submitForm (result: boolean) {console.log(result)
}Validate-Form属性和事件
form-submit 类型事件默认-说明回调参数 (result: boolean) void, result 代表是否通过了验证
Validate-Input属性和事件
rules 类型array默认-说明 单个输入框的验证类型可以传入包含特定对象的数组, 详情可见上面示例代码 tag 类型input | textarea默认input说明 根节点类型 v-model 类型 string默认-说明 支持 v-model请对响应式数据