init
This commit is contained in:
138
src/component/form/index.less
Normal file
138
src/component/form/index.less
Normal file
@@ -0,0 +1,138 @@
|
||||
.layui-form-item {
|
||||
margin-bottom: 20px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.layui-form-item-right .layui-form-label {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.layui-form-item-left .layui-form-label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.layui-form-item-top .layui-form-label {
|
||||
text-align: left;
|
||||
float: none;
|
||||
}
|
||||
|
||||
.layui-form-item-top > div {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.layui-form-item:after {
|
||||
content: "\20";
|
||||
clear: both;
|
||||
display: block;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.layui-form-label {
|
||||
float: left;
|
||||
display: block;
|
||||
width: 95px;
|
||||
padding-right: 15px;
|
||||
line-height: 38px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.layui-form-label-col {
|
||||
display: block;
|
||||
float: none;
|
||||
padding: 9px 0;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.layui-form-item .layui-inline {
|
||||
margin-bottom: 5px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.layui-input-block {
|
||||
margin-left: 110px;
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.layui-input-inline {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.layui-form-item .layui-input-inline {
|
||||
float: left;
|
||||
width: 190px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.layui-form-text .layui-input-inline {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.layui-form-mid {
|
||||
float: left;
|
||||
display: block;
|
||||
padding: 9px 0 !important;
|
||||
line-height: 20px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.layui-form-danger + .layui-form-select .layui-input,
|
||||
.layui-form-danger:focus {
|
||||
border-color: #ff5722 !important;
|
||||
}
|
||||
|
||||
.layui-form-item .layui-form-checkbox {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.layui-form-item .layui-form-checkbox[lay-skin="primary"] {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.layui-required {
|
||||
color: #ff5722;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.layui-form .layui-form-item {
|
||||
.layui-input-block,
|
||||
.layui-input-inline {
|
||||
.layui-form-danger {
|
||||
&, .layui-textarea, .layui-tag-input, .layui-input {
|
||||
border-color: #ff5722 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layui-error-message {
|
||||
color: #ff5722;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
padding-top: 5px;
|
||||
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);
|
||||
}
|
||||
}
|
||||
5
src/component/form/index.ts
Normal file
5
src/component/form/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { withInstall, WithInstallType } from "../../utils";
|
||||
import Component from "./index.vue";
|
||||
|
||||
const component: WithInstallType<typeof Component> = withInstall(Component);
|
||||
export default component;
|
||||
157
src/component/form/index.vue
Normal file
157
src/component/form/index.vue
Normal file
@@ -0,0 +1,157 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "LayForm",
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import "./index.less";
|
||||
import { toRefs, provide, reactive, onMounted } from "vue";
|
||||
import { Rule, ValidateError, ValidateMessages } from "async-validator";
|
||||
import { LayFormItemContext, FormCallback, modelType } from "../../types/form";
|
||||
|
||||
export interface FormProps {
|
||||
model?: modelType;
|
||||
required?: boolean;
|
||||
rules?: Rule;
|
||||
initValidate?: boolean;
|
||||
requiredIcons?: string;
|
||||
requiredErrorMessage?: string;
|
||||
validateMessage?: ValidateMessages;
|
||||
useCN?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<FormProps>(), {
|
||||
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>
|
||||
Reference in New Issue
Block a user