1. 封装组件DymanicForm.vue
- 使用
component
实现动态组件 - 组件不能直接使用字符串传入,所以根据传入的组件名称找到对应的组件
- 校验规则,可使用rule传入自定义规则,也可以使用封装好的基本规则 示例中使用了
checkRequired
- 暴露重置方法和校验方法
<template>
<el-form
:model="currentValue"
ref="dymanicForm"
v-bind="$attrs"
@submit.native.prevent
>
<el-form-item
:prop="index"
:rules="item.rules"
v-for="(item, index) in currentSchema"
:key="index"
v-bind="item.formItem || {}"
>
<component
v-model="currentValue[index]"
:is="item.componentName"
v-bind="item"
v-on="item.methods || {}"
/>
</el-form-item>
<slot />
</el-form>
</template>
<script lang="ts" setup>
import checkValidator from "~/utils/validator/index";
import {
ElInput,
ElSelect,
ElDatePicker,
ElCheckbox,
ElRadio,
ElRadioGroup,
ElCheckboxGroup,
ElSwitch,
} from "element-plus";
const componentMap = {
ElInput: ElInput,
ElSelect: ElSelect,
ElDatePicker: ElDatePicker,
ElCheckbox: ElCheckbox,
ElRadio: ElRadio,
ElRadioGroup: ElRadioGroup,
ElCheckboxGroup: ElCheckboxGroup,
};
const props = defineProps({
schema: Object,
modelValue: [String, Number, Boolean, Array, Date, Object],
});
const emit = defineEmits(["update:modelValue"]);
const currentValue = computed({
get: () => props.modelValue,
set: (val) => emit("update:modelValue", val),
});
const currentSchema = computed(() => {
const schema = {};
for (const key in props.schema) {
let { visible = true, ...item } = props.schema[key];
// 动态表单的组件名
item.componentName = componentMap[item.componentName];
// 是否显示
visible =
typeof visible !== "function" ? visible : visible(currentValue, item);
if (visible) {
schema[key] = { clearable: true, ...item };
}
// 表单验证规则
if (schema[key].validator && schema[key].validator.length) {
if (!schema[key].rules) schema[key].rules = [];
schema[key].validator?.forEach(([valida, args]) => {
if (checkValidator[valida]) {
schema[key].rules.unshift(checkValidator[valida](args));
}
});
}
}
return schema;
});
const dymanicForm = ref(null);
const validate = (func) => {
if (typeof func === "function") {
dymanicForm.value.validate((valid) => {
func(valid);
});
} else {
return new Promise((resolve) => {
dymanicForm.value.validate((valid) => {
resolve(valid);
});
});
}
};
const resetFields = () => {
dymanicForm.value.resetFields();
};
defineExpose({
resetFields,
validate,
});
</script>
2. 调用组件示例
<template>
<div class="">
<DymanicForm
ref="formRef"
:inline="true"
:schema="schema"
v-model="searchValue"
>
<el-form-item>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</DymanicForm>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import type { ItemSchema } from "~/types/dymanic";
import DymanicForm from "~/components/DymanicForm.vue";
const formRef = ref<InstanceType<typeof DymanicForm>>();
const schema = ref<ItemSchema>({
userId: {
formItem: {
label: "用户ID:",
},
style: {
width: "200px",
},
componentName: "ElInput",
placeholder: "请输入用户ID",
maxlength: 20,
validator: [
[
"checkRequired",
{
msg: "用户ID不能为空",
},
],
],
},
username: {
formItem: {
label: "账号:",
},
style: {
width: "200px",
},
componentName: "ElInput",
placeholder: "请输入账号",
maxlength: 20,
},
name: {
formItem: { label: "用户名:" },
style: {
width: "200px",
},
componentName: "ElInput",
placeholder: "请输入用户名",
maxlength: 20,
},
});
const searchValue = reactive({
userId: "",
username: "",
name: "",
});
const handleQuery = () => {
formRef.value.validate((valid: boolean) => {
if (valid) {
console.log("查询", searchValue);
// 查询逻辑
}
});
};
const handleReset = () => {
formRef.value.resetFields();
};
</script>
<style lang="scss" scoped></style>
3. 校验规则示例
// 校验内容不能为空的验证
const checkRequired = ({ msg, trigger = ['blur'] }) => {
return {
required: true,
message: msg,
trigger,
}
}
export default checkRequired