赞
踩
日常业务开发中的,避免不了的要接触到表单开发,那么我们有必要了解表单的深入使用方法,及封装出适合自己业务的自定义表单组件,效果如下:
不是用ele和antdvue框架,实现自己的表单组件!!!
<template> <div class="validate-form-container"> <!-- 表单项的区域 --> <slot></slot> <!-- 底部提交按钮区域 --> <div class="sublit-area" @click="formSubmit"> <slot name="submit"> <!-- 后备按钮 --> <button class="btn primary-btn">提交</button> </slot> </div> </div> </template> <script lang="ts" setup> const formSubmit = () => { console.log('test....') } </script> <style scoped></style>
<ValidateForm> </ValidateForm>
页面效果
validateForm组件
<template> <div class="validate-form-container"> <!-- 表单项的区域 --> <slot></slot> <!-- 底部提交按钮区域 --> <div class="sublit-area" @click="formSubmit"> <slot name="submit"> <!-- 后备按钮 --> <button class="btn btn-primary">提交</button> </slot> </div> </div> </template> <script lang="ts" setup> import { defineEmits } from 'vue' const emitts = defineEmits(['form-submit']) const formSubmit = () => { console.log('test....') emitts('form-submit') } </script> <style scoped></style>
validateInput
<template> {{ inputRef.error }} <input :class="['form-control', { 'is-invalid': inputRef.error }]" @blur="validateInput" v-bind="$attrs" v-model="inputRef.val" /> <div v-if="inputRef.error" class="invalid-feedback"> {{ inputRef.message }} </div> </template> <script lang="ts" setup> import { reactive, computed, defineProps, defineEmits, PropType } from 'vue' import { RulesHelp } from '../App.vue' const props = defineProps({ modelValue: String, rules: Array as PropType<RulesHelp> }) const emitts = defineEmits(['update:modelValue']) const inputRef = reactive({ val: computed({ get: () => props.modelValue || '', set: (val) => { emitts('update:modelValue', val) } }), error: false, message: '' }) const regRules = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/ const validateInput = () => { if (props.rules) { const allPassed = props.rules.every((ele) => { let passed = true inputRef.message = ele.message switch (ele.type) { case 'required': passed = !!inputRef.val break case 'email': passed = regRules.test(inputRef.val) break case 'password': passed = inputRef.val.length >= 6 break default: break } return passed }) inputRef.error = !allPassed return allPassed } return true } </script> <style lang="less" scoped></style> ## 点击提交按钮后,验证所有的输入框
完整的源码
app.vue
<template> <div class="container-xxl"> <ValidateForm @form-submit="onFormSubmit"> <div class="mb-3"> <label class="form-label">Email address</label> <ValidateInput type="email" :rules="emalRules" placeholder="hello email" class="py-3" v-model="emailVal" ></ValidateInput> </div> <div class="mb-3"> <label class="form-label">Password</label> <ValidateInput :rules="passwordRules" type="password" placeholder="hello pwd" class="py-3" v-model="passwordVal" ></ValidateInput> </div> <template #submit> <button class="btn btn-primary">Submit</button> </template> </ValidateForm> </div> </template> <script lang="ts"> import { defineComponent, ref, reactive, onMounted } from 'vue' import ValidateForm from './components/ValidateForm1.vue' import ValidateInput from './components/ValidateInput1.vue' import mitt from 'mitt' interface RuleHelp { type: 'required' | 'email' | 'password' message: string } export const mitts = mitt() export type RulesHelp = RuleHelp[] export default defineComponent({ components: { ValidateForm, ValidateInput }, setup() { const emalRules: RulesHelp = [ { type: 'required', message: '邮箱不能为空' }, { type: 'email', message: '电子邮件格式不正确' } ] const emailVal = ref('') const passwordVal = ref() const passwordRules: RulesHelp = [ { type: 'required', message: '密码不能为空' }, { type: 'password', message: '密码长度不能少于6位' } ] /* const regRules = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/ */ const onFormSubmit = (value: boolean) => { console.log('999') if (value) { alert('验证成功') } else { alert('验证失败') } } return { onFormSubmit, emalRules, emailVal, passwordVal, passwordRules } } }) </script> <style lang="scss"> @import '~bootstrap/scss/bootstrap'; * { margin: 0; padding: 0; } ul { list-style: none; } #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; // text-align: center; color: #2c3e50; // margin-top: 60px; } .form-text-tip { color: red; } </style>
validateForm.vue
<template> <div class="validate-form-container"> <!-- 表单项的区域 --> <slot></slot> <!-- 底部提交按钮区域 --> <div class="sublit-area" @click="formSubmit"> <slot name="submit"> <!-- 后备按钮 --> <button class="btn btn-primary">提交</button> </slot> </div> </div> </template> <script lang="ts" setup> import { defineEmits, onMounted, onUnmounted } from 'vue' import { mitts } from '../App.vue' const emitts = defineEmits(['form-submit']) type FuncType = () => boolean const formSubmit = () => { console.log('test....', funcArr) const value = funcArr.map((ele) => ele()).every((result) => result) emitts('form-submit', value) } let funcArr: FuncType[] = [] const cb = (func: FuncType) => { console.log('mitts') if (func) { funcArr.push(func) } } /* on事件必须在emit事件之前注册好 */ //子组件是在onMounted挂在 //那么父组件必须在onMounted之前进行监听 mitts.on('form-item-create', cb as FuncType) onUnmounted(() => { mitts.off('form-item-create') funcArr = [] }) </script> <style scoped></style>
validateInput.vue
<template> <input :class="['form-control', { 'is-invalid': inputRef.error }]" @blur="validateInput" v-bind="$attrs" v-model="inputRef.val" /> <div v-if="inputRef.error" class="invalid-feedback"> {{ inputRef.message }} </div> </template> <script lang="ts" setup> import { reactive, computed, defineProps, defineEmits, PropType, onMounted, onUnmounted } from 'vue' import { mitts } from '../App.vue' import { RulesHelp } from '../App.vue' const props = defineProps({ modelValue: String, rules: Array as PropType<RulesHelp> }) const emitts = defineEmits(['update:modelValue']) const inputRef = reactive({ val: computed({ get: () => props.modelValue || '', set: (val) => { emitts('update:modelValue', val) } }), error: false, message: '' }) const regRules = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/ const validateInput = () => { if (props.rules) { const allPassed = props.rules.every((ele) => { let passed = true inputRef.message = ele.message switch (ele.type) { case 'required': passed = !!inputRef.val break case 'email': passed = regRules.test(inputRef.val) break case 'password': passed = inputRef.val.length >= 6 break default: break } return passed }) inputRef.error = !allPassed return allPassed } return true } onMounted(() => { mitts.emit('form-item-create', validateInput) }) </script> <style lang="less" scoped></style>
这样就基本实现了一个简单的自定义组件,大家可以尝试下。。。
扩展一个多行文本,textarea
validateInput.vue完整代码
<template> {{ inputRef.error }} <input v-if="tagType === 'input'" :class="['form-control', { 'is-invalid': inputRef.error }]" @blur="validateInput" v-bind="$attrs" v-model="inputRef.val" /> <textarea v-if="tagType === 'textarea'" :class="['form-control', { 'is-invalid': inputRef.error }]" @blur="validateInput" v-bind="$attrs" v-model="inputRef.val" /> <div v-if="inputRef.error" class="invalid-feedback"> {{ inputRef.message }} </div> </template> <script lang="ts" setup> import { reactive, computed, defineProps, defineEmits, PropType, onMounted, onUnmounted } from 'vue' import { mitts } from '../App.vue' import { RulesHelp } from '../App.vue' type TagType = 'input' | 'textarea' const props = defineProps({ modelValue: String, rules: Array as PropType<RulesHelp>, tagType: { type: String as PropType<TagType>, default: 'input' } }) const emitts = defineEmits(['update:modelValue']) const inputRef = reactive({ val: computed({ get: () => props.modelValue || '', set: (val) => { emitts('update:modelValue', val) } }), error: false, message: '' }) const regRules = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/ const validateInput = () => { if (props.rules) { const allPassed = props.rules.every((ele) => { let passed = true inputRef.message = ele.message switch (ele.type) { case 'required': passed = !!inputRef.val break case 'email': passed = regRules.test(inputRef.val) break case 'password': passed = inputRef.val.length >= 6 break default: break } return passed }) inputRef.error = !allPassed return allPassed } return true } onMounted(() => { mitts.emit('form-item-create', validateInput) }) </script> <style lang="less" scoped></style>
关注我的个人公众号,获取更多前后端开发经验知识
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。