iter: d17 表单错误态覆盖包裹式控件 + 校验时机事件
This commit is contained in:
@@ -26,7 +26,13 @@ export function formItem(props: FormItemProps, control: HTMLElement): FormItemHa
|
||||
const label = h('label', { class: 'ua-form-label' }, props.label, props.required ? h('i', { class: 'ua-form-req' }, '*') : null);
|
||||
const el = h('div', { class: 'ua-form-item' }, label, h('div', { class: 'ua-form-control' }, control, error));
|
||||
|
||||
/*** 执行全部规则:返回首个错误消息,同时同步错误区与控件态 ***/
|
||||
/*** 错误态落点:控件根 + 内部原生控件,保证 select / checkbox 这类包裹式控件也能标红 ***/
|
||||
const marked = (): HTMLElement[] => [
|
||||
control,
|
||||
...Array.from(control.querySelectorAll<HTMLElement>('input, textarea, select, .ua-select-trigger')),
|
||||
];
|
||||
|
||||
/*** 执行全部规则:返回首个错误消息,同时同步错误区、控件态与 aria-invalid ***/
|
||||
const validate = () => {
|
||||
const value = props.value();
|
||||
let msg: string | null = null;
|
||||
@@ -36,14 +42,18 @@ export function formItem(props: FormItemProps, control: HTMLElement): FormItemHa
|
||||
}
|
||||
error.textContent = msg ?? '';
|
||||
control.classList.toggle('ua-invalid', !!msg);
|
||||
for (const node of marked()) node.setAttribute('aria-invalid', String(!!msg)); // 读屏同步错误态
|
||||
return msg;
|
||||
};
|
||||
|
||||
control.addEventListener('input', () => {
|
||||
if (mode === 'input' || error.textContent) validate(); // input 模式即时校验;其余模式仅清已报错误
|
||||
});
|
||||
control.addEventListener('blur', () => {
|
||||
if (mode !== 'submit') validate();
|
||||
control.addEventListener('change', () => {
|
||||
if (mode === 'input') validate(); // select / checkbox / radio 变更即校验(原生 input 事件不冒泡)
|
||||
});
|
||||
control.addEventListener('focusout', () => {
|
||||
if (mode !== 'submit') validate(); // 用会冒泡的 focusout 取代 blur,包裹式控件同样生效
|
||||
});
|
||||
return { el, validate };
|
||||
}
|
||||
|
||||
@@ -1076,7 +1076,9 @@
|
||||
"把句柄数组交给 form:form({ onSubmit }, items),form 渲染全部字段 + 提交/重置按钮",
|
||||
"提交时逐项校验:全过触发 onSubmit;有错则标红控件、显示错误文案并聚焦首个出错项",
|
||||
"规则语义:required 非空(trim)、min/max 长度、pattern 正则、validator 自定义(true 通过 / 字符串为错误)",
|
||||
"非必填字段为空时跳过其余规则;Enter 键触发表单原生 submit(已拦截走校验流程)"
|
||||
"非必填字段为空时跳过其余规则;Enter 键触发表单原生 submit(已拦截走校验流程)",
|
||||
"错误态覆盖包裹式控件:标红作用于控件根与内部原生控件(含自绘 select 的触发器),并同步 aria-invalid,读屏与视觉一致",
|
||||
"触发时机用 input / change / focusout(均会冒泡),因此 checkbox / select / 单选组这类包裹式控件同样能失焦校验"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1003,8 +1003,13 @@
|
||||
.ua-form-error:empty {
|
||||
display: none;
|
||||
}
|
||||
/* 校验失败:控件描红 + 危险色光环 */
|
||||
.ua-invalid {
|
||||
/* 校验失败:控件描红 + 危险色光环(root 与包裹式控件的内部触发器一并覆盖) */
|
||||
.ua-invalid,
|
||||
.ua-invalid .ua-input,
|
||||
.ua-invalid .ua-textarea,
|
||||
.ua-invalid .ua-select-trigger,
|
||||
.ua-invalid .ua-radio,
|
||||
.ua-invalid .ua-slider-input {
|
||||
border-color: var(--ua-color-danger) !important;
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--ua-color-danger) 15%, transparent) !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user