修复 src 结构
This commit is contained in:
49
src/component/formItem/cnValidateMessage.ts
Normal file
49
src/component/formItem/cnValidateMessage.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { ValidateMessages } from "async-validator";
|
||||
// 中文翻译 --> 根据 async-validator 中 ValidateMessages 进行翻译
|
||||
export default {
|
||||
default: "%s验证失败",
|
||||
required: "%s不能为空",
|
||||
enum: "%s不在枚举%s里面",
|
||||
whitespace: "%s不能为空",
|
||||
date: {
|
||||
format: "%s日期%s不是一个有效格式的日期%s",
|
||||
parse: "%s无法解析为日期,%s是无效的",
|
||||
invalid: "%s日期%s是无效的",
|
||||
},
|
||||
types: {
|
||||
number: "%s不是一个有效的数字",
|
||||
boolean: "%s不是一个有效的布尔类型",
|
||||
method: "%s不是一个有效的方法",
|
||||
regexp: "%s不是一个有效的正则表达式",
|
||||
integer: "%s不是一个有效的整型数字",
|
||||
float: "%s不是一个有效的浮点小数",
|
||||
array: "%s不是一个有效的数组",
|
||||
object: "%s不是一个有效的对象",
|
||||
enum: "%s不是一个有效的枚举",
|
||||
date: "%s不是一个有效的日期",
|
||||
url: "%s不是一个有效的url",
|
||||
hex: "%s不是一个有效的十六进制",
|
||||
email: "%s不是一个有效的邮箱",
|
||||
},
|
||||
string: {
|
||||
len: "%s必须是长度为%s个字符",
|
||||
min: "%s最小长度为%s个字符",
|
||||
max: "%s最长%s个字符",
|
||||
range: "%s字符长度需要在%s和%s直接",
|
||||
},
|
||||
number: {
|
||||
len: "%s长度必须为%s",
|
||||
min: "%s必须小于%s",
|
||||
max: "%s必须大于%s",
|
||||
range: "%s需要在%s和%s之间",
|
||||
},
|
||||
array: {
|
||||
len: "%s长度必须为%s",
|
||||
min: "%s长度必须小于%s",
|
||||
max: "%s长度必须大于%s",
|
||||
range: "%s长度需要在%s和%s之间",
|
||||
},
|
||||
pattern: {
|
||||
mismatch: "%s值%s不能匹配%s",
|
||||
},
|
||||
} as ValidateMessages;
|
||||
48
src/component/formItem/index.less
Normal file
48
src/component/formItem/index.less
Normal file
@@ -0,0 +1,48 @@
|
||||
@error_color: red;
|
||||
|
||||
.layui-required {
|
||||
color: @error_color;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.layui-form .layui-form-item {
|
||||
.layui-input-block,
|
||||
.layui-input-inline {
|
||||
.layui-form-danger {
|
||||
&, .layui-input {
|
||||
border-color: #ff5722 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layui-error-message {
|
||||
color: @error_color;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
padding-top: 2px;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.layui-error-message-anim {
|
||||
-ms-transform-origin: 0 0;
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
-webkit-animation: layui-top-show-anim 0.3s ease 1;
|
||||
animation: layui-top-show-anim 0.3s ease 1;
|
||||
}
|
||||
|
||||
@keyframes layui-top-show-anim {
|
||||
0% {
|
||||
opacity: 0.3;
|
||||
transform: rotateX(45deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: rotateX(0);
|
||||
}
|
||||
}
|
||||
9
src/component/formItem/index.ts
Normal file
9
src/component/formItem/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { App } from "vue";
|
||||
import Component from "./index.vue";
|
||||
import type { IDefineComponent } from "../type/index";
|
||||
|
||||
Component.install = (app: App) => {
|
||||
app.component(Component.name || "LayFormItem", Component);
|
||||
};
|
||||
|
||||
export default Component as IDefineComponent;
|
||||
194
src/component/formItem/index.vue
Normal file
194
src/component/formItem/index.vue
Normal file
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div class="layui-form-item" ref="formItemRef">
|
||||
<label class="layui-form-label">
|
||||
<span
|
||||
v-if="props.prop && isRequired"
|
||||
:class="
|
||||
['layui-required', 'layui-icon'].concat(layForm.requiredIcons ?? '')
|
||||
"
|
||||
>
|
||||
<slot name="required" :props="{ ...props, model: layForm.model }">{{
|
||||
layForm.requiredIcons ? "" : "*"
|
||||
}}</slot>
|
||||
</span>
|
||||
<slot name="label" :props="{ ...props, model: layForm.model }">
|
||||
{{ label }}
|
||||
</slot>
|
||||
</label>
|
||||
<div :class="[mode ? 'layui-input-' + mode : '']">
|
||||
<div ref="slotParent">
|
||||
<slot :props="{ ...props, model: layForm.model }"></slot>
|
||||
</div>
|
||||
<span
|
||||
v-if="errorStatus"
|
||||
:class="[
|
||||
'layui-error-message',
|
||||
{ 'layui-error-message-anim': errorStatus },
|
||||
]"
|
||||
>{{ errorMsg }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup name="LayFormItem" lang="ts">
|
||||
import "./index.less";
|
||||
import {
|
||||
defineProps,
|
||||
inject,
|
||||
withDefaults,
|
||||
ref,
|
||||
reactive,
|
||||
toRefs,
|
||||
onMounted,
|
||||
computed,
|
||||
watch,
|
||||
} from "vue";
|
||||
import {
|
||||
layFormKey,
|
||||
LayFormContext,
|
||||
LayFormItemContext,
|
||||
FieldValidateError,
|
||||
} from "../type/form";
|
||||
import Schema, {
|
||||
Rule,
|
||||
RuleItem,
|
||||
Rules,
|
||||
ValidateCallback,
|
||||
ValidateError,
|
||||
ValidateMessages,
|
||||
} from "async-validator";
|
||||
import cnValidateMessage from "./cnValidateMessage";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
prop?: string;
|
||||
mode?: string;
|
||||
label?: string;
|
||||
errorMessage?: string;
|
||||
rules?: Rule;
|
||||
required?: boolean;
|
||||
}>(),
|
||||
{
|
||||
mode: "block",
|
||||
}
|
||||
);
|
||||
|
||||
const layForm = inject(layFormKey, {} as LayFormContext);
|
||||
const formItemRef = ref<HTMLDivElement>();
|
||||
const slotParent = ref<HTMLDivElement>();
|
||||
|
||||
// 是否必填
|
||||
const isRequired = computed(() => {
|
||||
return props.required || layForm.required;
|
||||
});
|
||||
|
||||
// 拼接校验规则
|
||||
const ruleItems = computed(() => {
|
||||
const prop = props.prop;
|
||||
if (!prop) {
|
||||
return {};
|
||||
}
|
||||
|
||||
let rulesArrs: RuleItem[] = [];
|
||||
if (isRequired.value) {
|
||||
rulesArrs.push({ required: true });
|
||||
}
|
||||
if (props.rules) {
|
||||
rulesArrs = rulesArrs.concat(props.rules as RuleItem | RuleItem[]);
|
||||
}
|
||||
if (layForm.rules && layForm.rules[prop]) {
|
||||
rulesArrs = rulesArrs.concat(layForm.rules[prop] as RuleItem | RuleItem[]);
|
||||
}
|
||||
return rulesArrs;
|
||||
});
|
||||
|
||||
// 值 计算 和 监听
|
||||
const filedValue = computed(() =>
|
||||
props.prop ? layForm.model[props.prop] : undefined
|
||||
);
|
||||
watch(
|
||||
() => filedValue.value,
|
||||
(val) => validate(),
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 错误状态和信息
|
||||
const errorStatus = ref(false);
|
||||
const errorMsg = ref();
|
||||
// 校验数据有效性
|
||||
const validate = (callback?: ValidateCallback) => {
|
||||
if (props.prop && (ruleItems.value as RuleItem[]).length > 0) {
|
||||
// 校验规则
|
||||
const descriptor: Rules = {};
|
||||
descriptor[layForm.useCN ? props.label || props.prop : props.prop] =
|
||||
ruleItems.value;
|
||||
const validator = new Schema(descriptor);
|
||||
|
||||
let model: { [key: string]: any } = {};
|
||||
let validateMessage = null;
|
||||
// 使用中文错误提示
|
||||
if (layForm.useCN) {
|
||||
validateMessage = Object.assign(
|
||||
{},
|
||||
cnValidateMessage,
|
||||
layForm.validateMessage
|
||||
);
|
||||
model[props.label || props.prop] = filedValue.value;
|
||||
} else {
|
||||
layForm.validateMessage && (validateMessage = layForm.validateMessage);
|
||||
model[props.prop] = filedValue.value;
|
||||
}
|
||||
// 自定义校验消息
|
||||
layForm.requiredErrorMessage &&
|
||||
(validateMessage = Object.assign(validateMessage, {
|
||||
required: layForm.requiredErrorMessage,
|
||||
}));
|
||||
validateMessage && validator.messages(validateMessage);
|
||||
|
||||
// 开始校验
|
||||
validator.validate(model, (errors, fields) => {
|
||||
errorStatus.value = errors !== null && errors.length > 0;
|
||||
const slotParentDiv = slotParent.value as HTMLDivElement;
|
||||
if (errorStatus.value) {
|
||||
const _errors = errors as FieldValidateError[];
|
||||
// 如果是中文,将错误信息转换成FieldValidateError类型
|
||||
layForm.useCN &&
|
||||
_errors.forEach((error) => {
|
||||
error.label = props.label;
|
||||
error.field = props.prop;
|
||||
});
|
||||
errorMsg.value = props.errorMessage ?? _errors[0].message;
|
||||
slotParentDiv.childElementCount > 0 &&
|
||||
slotParentDiv.firstElementChild?.classList.add("layui-form-danger");
|
||||
callback && callback(_errors, fields);
|
||||
} else {
|
||||
clearValidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 清除校验
|
||||
const clearValidate = () => {
|
||||
errorStatus.value = false;
|
||||
errorMsg.value = "";
|
||||
const slotParentDiv = slotParent.value as HTMLDivElement;
|
||||
slotParentDiv.childElementCount > 0 &&
|
||||
slotParentDiv.firstElementChild?.classList.remove("layui-form-danger");
|
||||
};
|
||||
|
||||
defineExpose({ validate, clearValidate });
|
||||
|
||||
onMounted(() => {
|
||||
if (props.prop) {
|
||||
layForm.addField(
|
||||
reactive({
|
||||
...toRefs(props),
|
||||
$el: formItemRef,
|
||||
validate,
|
||||
clearValidate,
|
||||
}) as LayFormItemContext
|
||||
);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user