老师你好,我是用setup语法糖和组合式API编写的。想知道是不是mitt() 的使用方法是否出错了?
仓库地址: https://git.imooc.com/Ak17/Vue3zheye_Ak17
具体问题表现如下:
我定义的存放校验函数数组 funcArr ,它重复传入了一次校验函数,本来是想应该就传入一次就好。具体表现为,添加验证函数到数组的方法 register ,页面在一加载时就执行了4次,我的预期时执行2次
定义了 const results = funcArr.value.map(func => func()) ,console.log("Validation results:", results)来验证,但在输入框内容正确与否的情况下,results的值为 undefined 的数组,而不是布尔值
下面附上两个组件的代码
// ValidateForm.vue <template> <form class="validate-form-container"> <slot name="default"></slot> <div class="submit-area"> <slot name="submit"> <button type="submit" class="btn btn-primary" @click.prevent="submitForm"> 提交 </button> </slot> </div> <div class="reset-area"> <slot name="reset"> <button type="submit" class="btn btn-danger" @click.prevent="clearInputs"> 重置 </button> </slot> </div> </form> </template> <script setup> import { emitter } from "./ValidateInput.vue" import { defineEmits, onUnmounted, ref } from "vue" // 自定义 hook,useValidateForm用于管理校验函数 type ValidateFunc = () => boolean const useValidateForm = (emit: (event: string, ...args: any[]) => void) => { // 校验函数数组 const funcArr = ref<ValidateFunc[]>([]) // 提交表单时校验所有函数,并发出相应事件 const submitForm = () => { // const result = funcArr.value.map(func => func()).every(result => result) // console.log("Form is submitting! reslut:" + result) // emit("form-submit", result) const results = funcArr.value.map(func => func()) console.log(funcArr.value) console.log("Validation results:", results) const result = results.every(result => result) console.log("Form is submitting!", result) emit("form-submit", result) } // 注册校验函数 const register = (func?: ValidateFunc) => { if (func) { funcArr.value.push(func) } console.log("register执行了") console.log("funcArr:", funcArr.value) } // 取消注册校验函数 const unregister = (func?: ValidateFunc) => { if (func) { const index = funcArr.value.indexOf(func) if (index !== -1) { funcArr.value.splice(index, 1) } } } // 清空校验函数数组 onUnmounted(() => { funcArr.value = [] emitter.off("form-item-created") }) return { submitForm, register, unregister, } } //自定义hook,clearForm用于清空输入框 type clearFunc = () => void const clearForm = (emit: (event: string, ...args: any[]) => void) => { const clearFuncArr = ref<clearFunc[]>([]) const clearInputs = () => { const result = clearFuncArr.value.map(func => func()) console.log("Form is cleared", result) emit("clear-inputs", result) } const clearReg = (func?: clearFunc) => { clearFuncArr.value.push(func) } onUnmounted(() => { clearFuncArr.value = [] emitter.off("form-item-cleared") }) return { clearInputs, clearReg, } } // 定义组件的自定义事件 const emits = defineEmits(["form-submit", "clear-inputs"]) // 创建自定义 hook 实例,用于维护校验函数数组并在组件销毁时释放资源 const { submitForm, register } = useValidateForm(emits) // 创建自定义 hook 实例,用于清空输入框 const { clearInputs, clearReg } = clearForm(emits) //监听传过来的验证方法 // onMounted(() => { emitter.on("form-item-created", (func?: ValidateFunc) => { if (func) { register(func) } }) emitter.on("form-item-cleared", (func?: clearFunc) => { if (func) { clearReg(func) } }) // }) </script>
//ValidateInput.vue <template> <div> <div class="validate-input-container pb-3"> <input type="text" class="form-control" :class="{ 'is-invalid': inputRef.error, 'is-valid': inputRef.allPassed }" v-model="inputRef.val" @blur="toValidate" @input="updateValue" /> <span v-if="inputRef.error" class="invalid-feedback">{{ inputRef.message }}</span> </div> </div> </template> <script> import mitt from "mitt" export const emitter = mitt() </script> <script setup> import { ref, reactive, inject } from "vue" export interface RuleProps { type: "required" | "email" | "pwdRange" message?: string //以下要两个属性配合range使用 min?: { message: string; minlength: number } max?: { message: string; maxlength: number } } export type RulePropsArr = RuleProps[] const props = defineProps<{ rules: RulePropsArr modelValue?: string validateType?: RuleProps["type"] //设置输入框验证类型 }>() const inputRef = reactive({ val: props.modelValue || "", error: false, message: "", //可编辑的提示信息 allPassed: false, }) //邮箱正则 const emailReg = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ //邮箱验证通过的逻辑 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 console.log("inputRef.error = " + inputRef.error) inputRef.allPassed = allPassed } } //密码验证通过的逻辑 const passwordInput = () => { if (props.rules) { const allPassed = props.rules.every(rule => { let passed = true switch (rule.type) { case "required": passed = inputRef.val.trim() !== "" inputRef.message = rule.message break case "pwdRange": if (inputRef.val.trim().length >= 6 && inputRef.val.trim().length <= 12) { passed = true inputRef.message = "密码长度正确" } else { passed = false inputRef.message = "密码长度需在六位至十二位" } break default: break } return passed }) inputRef.error = !allPassed } console.log("密码验证执行了") } const emit = defineEmits(["update:modelValue", "form-item-created", "form-item-cleared"]) // defineEmits格式是约定的, 1、默认 v-model 对应:'update:modelValue', 2、自定义v-model对应:'update:自定义变量名' const updateValue = (e: KeyboardEvent) => { const targetValue = (e.target as HTMLInputElement).value inputRef.val = targetValue emit("update:modelValue", targetValue) } //验证何种类型 const toValidate = computed(() => { if (props.validateType == "email") { return validateInput } else if (props.validateType == "pwdRange") { return passwordInput } }) const clearInputs = () => { inputRef.val = "" inputRef.message = "" console.log("重置执行了" + inputRef.error) } onMounted(() => { emitter.emit("form-item-created", validateInput) emitter.emit("form-item-created", passwordInput) emitter.emit("form-item-cleared", clearInputs) }) </script> <style scoped></style>
//App.vue <template> <el-container direction="vertical"> <GlobalHeader :user="currentUser"></GlobalHeader> <!-- <ColumnList :list="testData" /> --> <ValidateForm> <div class="mb-3"> <label class="form-label">邮箱地址</label> <ValidateInput :rules="currentInput" :validate-type="`email`"></ValidateInput> <label class="form-label">密码</label> <ValidateInput :rules="passwordInput" :validate-type="`pwdRange`"></ValidateInput> </div> </ValidateForm> <template #submit></template> <template #reset></template> </el-container> </template> <script setup> import ValidateInput, { RulePropsArr } from "./components/ValidateInput.vue" import ValidateForm from "./components/ValidateForm.vue" import "bootstrap/dist/css/bootstrap.min.css" //邮箱验证--传入ValidateInput组件的props.rules const currentInput: RulePropsArr = [ { type: "required", message: "邮箱地址不能为空" }, { type: "email", message: "请输入正确的邮箱地址" }, ] //密码验证--传入ValidateInput组件的props.rules const passwordInput: RulePropsArr = [ { type: "required", message: "密码不能为空" }, { type: "pwdRange", min: { message: "你的密码至少包含六位且不含空格", minlength: 6 } }, { type: "pwdRange", max: { message: "你的密码至多为十二位且不含空格", maxlength: 12 } }, ] </script>
清空内容的功能正常