Vue3.0
组件库之表单组件
从零搭建一.表单组件
Form
组件
1.表单组件用于接收表单数据和表单验证规则,没有任何实际功能
<template>
<form class="z-form">
<slot></slot>
</form>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
name:'ZForm',
props:{
model:Object, // 表单数据
rules:Object // 校验规则
},
emits:['validate'] // 表单验证
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FormItem
组件
2.用于实现表单验证逻辑
<template>
<div class="z-form-item">
<label v-if="label">{{ label }}</label>
<slot></slot>
<div class="z-form-item__error">
显示错误信息
</div>
</div>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
name:'ZFormItem',
props: {
label: String,
prop: String,
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
二.数据交互实现
父组件提供数据给子组件,并收集
formItem
组件实例
const formMitt = mitt(); // 用于子组件触发事件
const zForm = reactive({
// 用于提供给子组件
...toRefs(props),
formMitt,
});
provide("zForm", zForm); // 暴露数据
const fields = []; // 用于收集子组件实例
formMitt.on("z.form.add", (field) => {
fields.push(field);
});
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
子组件将自己的validate方法传递给父组件。并监听输入框事件
const formItemMitt = mitt();
const zFormItem = reactive({
...toRefs(props),
formItemMitt,
validate, // 提供一个最核心的方法validate,好让父级可以调用到此方法
});
provide("zFormItem", zFormItem); // 提供给其他组件使用 checkbox,input
const zForm = inject("zForm", {} as ZFormContext);
const getRules = (): any[] => {
// 获取规则 ,并且绑定事件
return zForm.rules[props.prop] as any[];
};
const addValidateEvents = () => {
// 绑定事件
const rules: any[] = getRules();
if (rules && rules.length > 0) {
formItemMitt.on("z.form.blur", onFieldBlur);
formItemMitt.on("z.form.change", onFieldChange);
}
};
onMounted(() => {
zForm.formMitt?.emit("z.form.add", zFormItem); // 将自己传递给父组件
addValidateEvents(); // 添加验证事件,子组件会触发这些事件
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
三.监控输入框中的内容
得到输入框中的内容进行校验
const validateState = ref("");
const validateMessage = ref("");
const getFilteredRule = (trigger) => {
// 根据触发方式获得对应的规则
const rules: any[] = getRules();
return rules
.filter((rule) => {
if (!rule.trigger || trigger == "") return true;
if (Array.isArray(rule.trigger)) {
return rule.trigger.indexOf(trigger) > -1; // 说明有
} else {
return rule.trigger === trigger;
}
}).map((rule) => ({ ...rule }));
};
const validate = (trigger, callback?) => {
const rules = getFilteredRule(trigger); // 获取过滤后的规则
if (!rules || rules.length == 0) return;
const descriptor = {};
rules.forEach((rule) => {
delete rule.trigger;
});
descriptor[props.prop] = rules;
// 校验器
const validator = new AsyncValidator(descriptor);
// 数据值
const model = {};
model[props.prop] = zForm.model[props.prop];
// 使用async-validate校验内容
validator.validate(model, {}, (errors: any, invalidFields: any) => {
validateState.value = !errors ? "success" : "error";
validateMessage.value = errors ? errors[0].message : "";
callback?.(validateMessage.value, invalidFields);
});
};
// 提供给儿子用
const onFieldBlur = () => {
validate("blur");
};
const onFieldChange = () => {
validate("change");
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
四.暴露校验方法
const validate = (callback?) => {
// 这里需要触发所有子组件的校验方法
let valid = true;
let invalidFields = {};
let count = 0;
let promise: Promise<boolean> | undefined;
if (typeof callback !== "function") {
promise = new Promise((resolve, reject) => {
callback = function (valid, invalidFields) {
if (valid) resolve(true);
reject(invalidFields);
};
});
}
for (const field of fields) {
field.validate("", (message, field) => {
if (message) {
valid = false;
}
invalidFields = { ...invalidFields, ...field };
console.log(count);
if (++count === fields.length) {
callback(valid, invalidFields);
}
});
}
return promise;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28