第三方庫 mitt
ValidateForm.vue
<template> <form class="validata-input-container" > <slot></slot> <div class="submit-area" > <slot name="submit"> <button @click.prevent="submitForm" type="submit" class="btn btn-primary me-md-2">提交</button> <button @click.prevent="clearInput" type="submit" class="btn btn-primary">重置</button> </slot> </div> </form> </template> <script lang="ts"> import { defineComponent, onUnmounted } from 'vue' import mitt from 'mitt' // 監聽器 type validateFun = () => boolean export const emitter = mitt() export default defineComponent({ emits: ['form-submit'], setup (props, context) { let funArr: validateFun[] = [] const submitForm = () => { const result = funArr.map(func => func()).every(result => result) console.log(result) context.emit('form-submit', result) } const callback = (func?: validateFun) => { if (func) { funArr.push(func) } } const clearInput = () => { emitter.emit('form-clear-input') } // 綁定事件 emitter.on('form-item-created', callback) onUnmounted(() => { emitter.off('form-item-created', callback) funArr = [] }) return { submitForm, clearInput } } }) </script>
ValidateInput.vue
<template> <div class="validata-input-container pb-3"> <input v-if="tag !== 'textarea'" :class="{'is-invalid': inputRef.error}" v-bind="$attrs" :value="inputRef.val" @input="upDateValue" @blur="vaildateEmail" class="form-control" aria-describedby="emailHelp"> <textarea v-else :class="{'is-invalid': inputRef.error}" v-bind="$attrs" :value="inputRef.val" @input="upDateValue" @blur="vaildateEmail" class="form-control"> </textarea> <span v-if="inputRef.error" class="invalid-feedback">{{inputRef.message}}</span> </div> </template> <script lang="ts"> import { defineComponent, PropType, reactive, onMounted, onUnmounted } from 'vue' import mitt from 'mitt' import { emitter } from './ValidateForm.vue' const emailReg = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/ const passwordReg = /^[a-zA-Z0-9]{6,}$/ interface RuleProp { type: 'required' | 'email' | 'password' | 'textarea' | 'custom', message: string, validator?: () => boolean } export const emitterClear = mitt() export type TagType = 'input' | 'textarea' // 創建一個數組類型的類型 export type RulesProp = RuleProp[] export default defineComponent({ props: { rules: Array as PropType<RulesProp>, modelValue: String, tag: { type: String as PropType<TagType>, default: 'input' } }, inheritAtter: false, setup (props, context) { const inputRef = reactive({ val: props.modelValue || '', error: false, message: '' }) const upDateValue = (e: KeyboardEvent) => { const targeValue = (e.target as HTMLInputElement).value inputRef.val = targeValue context.emit('update:modelValue', targeValue) } const vaildateEmail = () => { if (props.rules) { const allPass = 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 case 'password': passed = passwordReg.test(inputRef.val) break case 'custom': passed = rule.validator ? rule.validator() : true break default: break } return passed }) inputRef.error = !allPass return allPass } return true } onMounted(() => { emitter.emit('form-item-created', vaildateEmail) }) const clearInputS = () => { console.log(inputRef.val) inputRef.val = '' } emitter.on('form-clear-input', clearInputS) onUnmounted(() => { emitter.off('form-clear-input', clearInputS) }) return { inputRef, vaildateEmail, upDateValue } } }) </script>