vue3简单form表单封装

624 阅读1分钟

vue3表单组件的封装

本组件只简单封装了输入框的类型,其他类型可自行拓展~~ 效果图:

image.png

image.png

本项目依赖库:

bootstrap:样式库

mitt: vue3全局事件(相当于vue2的中央事件总线bus);

开始无脑撸代码~~~~~~~~

1、安装依赖

npm install bootstrap mitt -D
//bootstrap记得在main.ts中引入
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.min.js'

2、引入mitt(mitt具体用法参考上述mitt地址链接)

util/hooks文件下新建mitt.ts文件

代码如下:

import mitt from "mitt";
export type Fun = () => Boolean;
type Events = {
    listenSubmit: Fun;
    bar?: number;
};
export const emitter = mitt<Events>();

3、表单验证规则

util/hooks文件下新建common.ts文件

代码如下:

export interface ruleProp {
    type: "required" | 'email' | 'phone' | 'rang',
    message: string
}
export type rule = ruleProp[];

4、新建validate.vue组件

<template>
    <div>
        <form class="row">
            <div class="col-3"></div>
            <div class="mb-3 col-6">
                <label for="validationServer05" class="form-label">{{ attrs.label }}</label>
                <input v-bind="attrs" ref="ipt" @blur="changeValue" :value="iptRef.value" @input="getchangeValue"
                    class="form-control" :class="!isError ? 'is-invalid' : ''"
                    aria-describedby="validationServer05Feedback">
                <div v-if="!isError" class="invalid-feedback">
                    {{ iptRef.message }}
                </div>
            </div>
        </form>
    </div>
</template>
<script lang='ts' setup>
import { PropType, defineProps, onMounted, reactive, ref, useAttrs } from 'vue';
import { rule } from "../util/hooks/common";
import { emitter } from "../util/hooks/mitt";
const attrs = useAttrs();
const prop = defineProps({
    rules: Array as PropType<rule>,
    modelValue: String,
})
const emit = defineEmits(["update:modelValue"]);
let reg = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/
const isError = ref<undefined | boolean>(true)
const iptRef = reactive({
    value: prop.modelValue || "",
    message: "",
});
const getchangeValue = (e: Event) => {
    const val = (e.target as HTMLInputElement).value;
    iptRef.value = val;
    emit("update:modelValue", iptRef.value)
}
const changeValue = () => {
    isError.value = true;
    if (!prop.rules) return true;
    let res = prop.rules.every((item) => {
        let pass = false;
        iptRef.message = item.message;
        switch (item.type) {
            case "required":
                pass = (iptRef.value != "");
                break;
            case "email":
                pass = (reg.test(iptRef.value));
                break;
            default:
                pass = false
                break;
        }
        return pass;
    })
    isError.value = res;
    return res;
}
onMounted(() => {
    emitter.emit("listenSubmit", changeValue)
})
</script>
<style scoped>
.mb {
    margin-top: 20px;
}
</style>

5、新建form组件

<template>
    <div>
        <form class="form-content" onsubmit="return false">
            <slot name="default"></slot>
            <div class="form-submit" @click="handleSubmit">
                <slot name="submit">
                    <button class="btn btn-primary">提交</button>
                </slot>
            </div>
        </form>
    </div>
</template>

<script lang='ts' setup>
import { defineEmits, onUnmounted, reactive, toRefs } from 'vue';
import { emitter, Fun } from "../util/hooks/mitt";
let iptArr: Fun[] = [];
const callBack = (params: Fun) => {
    iptArr.push(params)
    console.log(iptArr);
}
emitter.on("listenSubmit", callBack);
/* 组件销毁同时停止监听 */
onUnmounted(() => {
    emitter.off("listenSubmit", () => { iptArr = [] })
})
const emits = defineEmits<{ (e: 'submitForm', params: boolean): void }>();
/* 表单提交 */
const handleSubmit = () => {
    let res = iptArr.every(item => {
        return item();
    })
    emits("submitForm", res)
}
</script>
<style scoped></style>

6、验证使用

<template>
    <form-com @submitForm="submitForm">
        <validate-com :rules="rules" placeholder="请输入账户" type="text" label="邮箱" 
            v-model="validateValue.emial"></validate-com>
        <validate-com :rules="rulePassword" placeholder="请输入密码" type="password" label="密码" v-model="validateValue.password"></validate-com>
        <template #submit>
            <button class="btn btn-danger">提交表单</button>
        </template>
    </form-com>

    <!-- <div>{{ validateValue }}</div> -->
</template>
<script lang='ts' setup>
import { reactive } from 'vue'
import validateCom from "../components/validate.vue"
import formCom from "../components/form.vue"
import { rule } from "../util/hooks/common";
let validateValue = reactive({
    emial: "",
    password: ""
})
/* 邮箱验证*/
const rules: rule = [{
    type: "required",
    message: "请输入文字"
}, {
    type: "email",
    message: "邮箱格式不正确"
}]
/* 密码验证 */
const rulePassword: rule = [{
    type: "required",
    message: "请输入密码"
}]
/* 获取表单数据 */
const submitForm = (val: boolean) => {
    console.log("~~~~~表单提交结果", val);
    if (val) {
        alert("表单提交")
    } else {
        alert("表单未提交")
    }
}
</script>
<style scoped></style>


theme: juejin highlight: a11y-dark