我的mitt() 的使用方法是否出错了?funcArr.value.map(func => func()) 遍历的结果有错误
来源:5-13 学习任务:扩展ValidateForm的功能,完成清空功能
阿康喜欢蓝色
2023-05-31
老师你好,我是用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>清空内容的功能正常
写回答
1回答
-
同学你好
原因是在这里:
你在 input 中发射了两次创建的事件啊~ emitter.emit("form-item-created", validateInput) emitter.emit("form-item-created", passwordInput) // 所以自然,每个 input 会有两个事件 所以你这里不应该是发送两个函数,而是要将两个函数整合为一个 validateInput 这个 validateInput 中应该包含所有验证的逻辑 参看: https://git.imooc.com/coding-449/zheye/src/develop/src/components/ValidateInput.vue#L66// 当然上面的链接是 develop 的实现,要复杂一些,包含最后的一系列功能,你酌情参考就行
112023-06-01
相似问题


