161 lines
4.0 KiB
Vue
161 lines
4.0 KiB
Vue
<script lang="ts">
|
|
export default {
|
|
name: "LayForm",
|
|
};
|
|
</script>
|
|
|
|
<script setup lang="ts">
|
|
import { toRefs, provide, reactive, onMounted } from "vue";
|
|
import { Rule, ValidateError, ValidateMessages } from "async-validator";
|
|
import {
|
|
LayFormItemContext,
|
|
FormCallback,
|
|
modelType,
|
|
} from "../../types/form";
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
model?: modelType;
|
|
required?: boolean;
|
|
rules?: Rule;
|
|
initValidate?: boolean;
|
|
requiredIcons?: string;
|
|
requiredErrorMessage?: string;
|
|
validateMessage?: ValidateMessages;
|
|
useCN?: boolean;
|
|
}>(),
|
|
{
|
|
model: function () {
|
|
return {};
|
|
},
|
|
useCN: true,
|
|
requiredIcons: "",
|
|
initValidate: false,
|
|
}
|
|
);
|
|
|
|
const formItems: LayFormItemContext[] = [];
|
|
const formItemMap: { [key: string]: LayFormItemContext } = {};
|
|
|
|
const emit = defineEmits(["submit"]);
|
|
|
|
// 初始化表单就进行校验
|
|
onMounted(() => {
|
|
props.initValidate && validate()?.catch((err) => {});
|
|
});
|
|
|
|
// 原生提交表单事件
|
|
const submit = function () {
|
|
let _isValidate = false;
|
|
validate((isValidate, model, errors) => {
|
|
_isValidate = isValidate as boolean;
|
|
emit("submit", isValidate, model, errors);
|
|
});
|
|
|
|
// 如果表单失败则阻止提交表单,成功则进行提交表单
|
|
return _isValidate;
|
|
};
|
|
|
|
/**
|
|
* 校验表单数据
|
|
* @param fields 需要校验的表单字段(string|string[]); 该字段如果为function, 则默认为回调函数,校验全部字段;
|
|
* @param callback 校验表单之后的回调函数
|
|
**/
|
|
const validate = function (
|
|
fields?: string | string[] | FormCallback | null,
|
|
callback?: FormCallback | null
|
|
) {
|
|
// 根据参数识别需要校验的表单项
|
|
let validateItems: LayFormItemContext[] = formItems;
|
|
if (typeof fields === "function") {
|
|
callback = fields;
|
|
} else if (
|
|
typeof fields === "string" ||
|
|
(Array.isArray(fields) && fields.length > 0)
|
|
) {
|
|
validateItems = [];
|
|
const validateFields = !fields ? [] : ([] as string[]).concat(fields);
|
|
validateFields.forEach(
|
|
(field) => formItemMap[field] && validateItems.push(formItemMap[field])
|
|
);
|
|
}
|
|
// 通过调用每个子项进行校验
|
|
let errorsArrs: ValidateError[] = [];
|
|
validateItems.forEach((filed) => {
|
|
filed.validate((errors, _fields) => {
|
|
errorsArrs = errorsArrs.concat(errors as ValidateError[]);
|
|
});
|
|
});
|
|
const isValidate = errorsArrs.length === 0;
|
|
// 有回调则进行回调
|
|
if (typeof callback === "function") {
|
|
isValidate
|
|
? callback(true, props.model, null)
|
|
: callback(false, props.model, errorsArrs);
|
|
return null;
|
|
}
|
|
|
|
// 没有回调则创建一个Promise的链式调用
|
|
return new Promise((resolve, reject) => {
|
|
const callbackParams = {
|
|
isValidate,
|
|
model: props.model,
|
|
errors: isValidate ? null : errorsArrs,
|
|
};
|
|
callbackParams.isValidate
|
|
? resolve(callbackParams)
|
|
: reject(callbackParams);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* 清除校验
|
|
* @param fields 需要进行清除校验的表单字段(string|string[]); 该字段如果为null, 则默认为全部字段清除校验;
|
|
**/
|
|
const clearValidate = function (fields?: string | string[]) {
|
|
const clearFields = !fields ? [] : ([] as string[]).concat(fields);
|
|
if (clearFields.length === 0) {
|
|
formItems.forEach((filed) => filed.clearValidate());
|
|
} else {
|
|
clearFields.forEach(
|
|
(field) => formItemMap[field] && formItemMap[field].clearValidate()
|
|
);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 重置表单所有值
|
|
**/
|
|
const reset = function () {
|
|
for (const key in props.model) {
|
|
props.model[key] = null;
|
|
}
|
|
// 重新校验
|
|
setTimeout(() => validate()?.catch((err) => {}), 0);
|
|
};
|
|
|
|
// 添加子项
|
|
const addField = function (item: LayFormItemContext) {
|
|
formItems.push(item);
|
|
formItemMap[item.prop as string] = item;
|
|
};
|
|
|
|
defineExpose({ validate, clearValidate, reset });
|
|
|
|
provide(
|
|
'LayForm',
|
|
reactive({
|
|
formItems,
|
|
addField,
|
|
clearValidate,
|
|
validate,
|
|
...toRefs(props),
|
|
})
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<form class="layui-form" :onsubmit="submit">
|
|
<slot></slot>
|
|
</form>
|
|
</template> |